PageRenderTime 60ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/add-ons/PHPExcel/PHPExcel/Writer/HTML.php

https://github.com/jcplat/console-seolan
PHP | 1257 lines | 632 code | 188 blank | 437 comment | 126 complexity | c13f50408de5ed3bf91bd10bb868bba2 MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, GPL-3.0, Apache-2.0, BSD-3-Clause
  1. <?php
  2. /**
  3. * PHPExcel
  4. *
  5. * Copyright (c) 2006 - 2009 PHPExcel
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * @category PHPExcel
  22. * @package PHPExcel_Writer
  23. * @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
  24. * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
  25. * @version 1.7.1, 2009-11-02
  26. */
  27. /** PHPExcel root directory */
  28. if (!defined('PHPEXCEL_ROOT')) {
  29. /**
  30. * @ignore
  31. */
  32. define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
  33. }
  34. /** PHPExcel_IWriter */
  35. require_once PHPEXCEL_ROOT . 'PHPExcel/Writer/IWriter.php';
  36. /** PHPExcel_Cell */
  37. require_once PHPEXCEL_ROOT . 'PHPExcel/Cell.php';
  38. /** PHPExcel_RichText */
  39. require_once PHPEXCEL_ROOT . 'PHPExcel/RichText.php';
  40. /** PHPExcel_Shared_Drawing */
  41. require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/Drawing.php';
  42. /** PHPExcel_Shared_String */
  43. require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/String.php';
  44. /** PHPExcel_HashTable */
  45. require_once PHPEXCEL_ROOT . 'PHPExcel/HashTable.php';
  46. /**
  47. * PHPExcel_Writer_HTML
  48. *
  49. * @category PHPExcel
  50. * @package PHPExcel_Writer
  51. * @copyright Copyright (c) 2006 - 2009 PHPExcel (http://www.codeplex.com/PHPExcel)
  52. */
  53. class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter {
  54. /**
  55. * PHPExcel object
  56. *
  57. * @var PHPExcel
  58. */
  59. protected $_phpExcel;
  60. /**
  61. * Sheet index to write
  62. *
  63. * @var int
  64. */
  65. private $_sheetIndex;
  66. /**
  67. * Pre-calculate formulas
  68. *
  69. * @var boolean
  70. */
  71. private $_preCalculateFormulas = true;
  72. /**
  73. * Images root
  74. *
  75. * @var string
  76. */
  77. private $_imagesRoot = '.';
  78. /**
  79. * Use inline CSS?
  80. *
  81. * @var boolean
  82. */
  83. private $_useInlineCss = false;
  84. /**
  85. * Array of CSS styles
  86. *
  87. * @var array
  88. */
  89. private $_cssStyles = null;
  90. /**
  91. * Array of column widths in points
  92. *
  93. * @var array
  94. */
  95. private $_columnWidths = null;
  96. /**
  97. * Default font
  98. *
  99. * @var PHPExcel_Style_Font
  100. */
  101. private $_defaultFont;
  102. /**
  103. * Flag whether spans have been calculated
  104. *
  105. * @var boolean
  106. */
  107. private $_spansAreCalculated;
  108. /**
  109. * Excel cells that should not be written as HTML cells
  110. *
  111. * @var array
  112. */
  113. private $_isSpannedCell;
  114. /**
  115. * Excel cells that are upper-left corner in a cell merge
  116. *
  117. * @var array
  118. */
  119. private $_isBaseCell;
  120. /**
  121. * Excel rows that should not be written as HTML rows
  122. *
  123. * @var array
  124. */
  125. private $_isSpannedRow;
  126. /**
  127. * Is the current writer creating PDF?
  128. *
  129. * @var boolean
  130. */
  131. protected $_isPdf = false;
  132. /**
  133. * Create a new PHPExcel_Writer_HTML
  134. *
  135. * @param PHPExcel $phpExcel PHPExcel object
  136. */
  137. public function __construct(PHPExcel $phpExcel) {
  138. $this->_phpExcel = $phpExcel;
  139. $this->_defaultFont = $this->_phpExcel->getDefaultStyle()->getFont();
  140. $this->_sheetIndex = 0;
  141. $this->_imagesRoot = '.';
  142. $this->_spansAreCalculated = false;
  143. $this->_isSpannedCell = array();
  144. $this->_isBaseCell = array();
  145. $this->_isSpannedRow = array();
  146. }
  147. /**
  148. * Save PHPExcel to file
  149. *
  150. * @param string $pFileName
  151. * @throws Exception
  152. */
  153. public function save($pFilename = null) {
  154. // garbage collect
  155. $this->_phpExcel->garbageCollect();
  156. $saveArrayReturnType = PHPExcel_Calculation::getArrayReturnType();
  157. PHPExcel_Calculation::setArrayReturnType(PHPExcel_Calculation::RETURN_ARRAY_AS_VALUE);
  158. // Build CSS
  159. $this->buildCSS(!$this->_useInlineCss);
  160. // Open file
  161. $fileHandle = fopen($pFilename, 'w');
  162. if ($fileHandle === false) {
  163. throw new Exception("Could not open file $pFilename for writing.");
  164. }
  165. // Write headers
  166. fwrite($fileHandle, $this->generateHTMLHeader(!$this->_useInlineCss));
  167. // Write data
  168. fwrite($fileHandle, $this->generateSheetData());
  169. // Write footer
  170. fwrite($fileHandle, $this->generateHTMLFooter());
  171. // Close file
  172. fclose($fileHandle);
  173. PHPExcel_Calculation::setArrayReturnType($saveArrayReturnType);
  174. }
  175. /**
  176. * Map VAlign
  177. */
  178. private function _mapVAlign($vAlign) {
  179. switch ($vAlign) {
  180. case PHPExcel_Style_Alignment::VERTICAL_BOTTOM: return 'bottom';
  181. case PHPExcel_Style_Alignment::VERTICAL_TOP: return 'top';
  182. case PHPExcel_Style_Alignment::VERTICAL_CENTER:
  183. case PHPExcel_Style_Alignment::VERTICAL_JUSTIFY: return 'middle';
  184. default: return 'baseline';
  185. }
  186. }
  187. /**
  188. * Map HAlign
  189. *
  190. * @return string|false
  191. */
  192. private function _mapHAlign($hAlign) {
  193. switch ($hAlign) {
  194. case PHPExcel_Style_Alignment::HORIZONTAL_GENERAL: return false;
  195. case PHPExcel_Style_Alignment::HORIZONTAL_LEFT: return 'left';
  196. case PHPExcel_Style_Alignment::HORIZONTAL_RIGHT: return 'right';
  197. case PHPExcel_Style_Alignment::HORIZONTAL_CENTER: return 'center';
  198. case PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY: return 'justify';
  199. default: return false;
  200. }
  201. }
  202. /**
  203. * Map border style
  204. */
  205. private function _mapBorderStyle($borderStyle) {
  206. switch ($borderStyle) {
  207. case PHPExcel_Style_Border::BORDER_NONE: return '0px';
  208. case PHPExcel_Style_Border::BORDER_DASHED: return '1px dashed';
  209. case PHPExcel_Style_Border::BORDER_DOTTED: return '1px dotted';
  210. case PHPExcel_Style_Border::BORDER_DOUBLE: return '3px double';
  211. case PHPExcel_Style_Border::BORDER_THICK: return '2px solid';
  212. default: return '1px solid'; // map others to thin
  213. }
  214. }
  215. /**
  216. * Get sheet index
  217. *
  218. * @return int
  219. */
  220. public function getSheetIndex() {
  221. return $this->_sheetIndex;
  222. }
  223. /**
  224. * Set sheet index
  225. *
  226. * @param int $pValue Sheet index
  227. * @return PHPExcel_Writer_HTML
  228. */
  229. public function setSheetIndex($pValue = 0) {
  230. $this->_sheetIndex = $pValue;
  231. return $this;
  232. }
  233. /**
  234. * Write all sheets (resets sheetIndex to NULL)
  235. */
  236. public function writeAllSheets() {
  237. $this->_sheetIndex = null;
  238. }
  239. /**
  240. * Generate HTML header
  241. *
  242. * @param boolean $pIncludeStyles Include styles?
  243. * @return string
  244. * @throws Exception
  245. */
  246. public function generateHTMLHeader($pIncludeStyles = false) {
  247. // PHPExcel object known?
  248. if (is_null($this->_phpExcel)) {
  249. throw new Exception('Internal PHPExcel object not set to an instance of an object.');
  250. }
  251. // Construct HTML
  252. $html = '';
  253. $html .= '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">' . "\r\n";
  254. $html .= '<!-- Generated by PHPExcel - http://www.phpexcel.net -->' . "\r\n";
  255. $html .= '<html>' . "\r\n";
  256. $html .= ' <head>' . "\r\n";
  257. $html .= ' <meta http-equiv="Content-Type" content="text/html; charset=utf-8">' . "\r\n";
  258. $html .= ' <title>' . htmlspecialchars($this->_phpExcel->getProperties()->getTitle()) . '</title>' . "\r\n";
  259. if ($pIncludeStyles) {
  260. $html .= $this->generateStyles(true);
  261. }
  262. $html .= ' </head>' . "\r\n";
  263. $html .= '' . "\r\n";
  264. $html .= ' <body>' . "\r\n";
  265. // Return
  266. return $html;
  267. }
  268. /**
  269. * Generate sheet data
  270. *
  271. * @return string
  272. * @throws Exception
  273. */
  274. public function generateSheetData() {
  275. // PHPExcel object known?
  276. if (is_null($this->_phpExcel)) {
  277. throw new Exception('Internal PHPExcel object not set to an instance of an object.');
  278. }
  279. // Ensure that Spans have been calculated?
  280. if (!$this->_spansAreCalculated) {
  281. $this->_calculateSpans();
  282. }
  283. // Fetch sheets
  284. $sheets = array();
  285. if (is_null($this->_sheetIndex)) {
  286. $sheets = $this->_phpExcel->getAllSheets();
  287. } else {
  288. $sheets[] = $this->_phpExcel->getSheet($this->_sheetIndex);
  289. }
  290. // Construct HTML
  291. $html = '';
  292. // Loop all sheets
  293. $sheetId = 0;
  294. foreach ($sheets as $sheet) {
  295. // Get cell collection
  296. $cellCollection = $sheet->getCellCollection();
  297. // Write table header
  298. $html .= $this->_generateTableHeader($sheet);
  299. // Get worksheet dimension
  300. $dimension = explode(':', $sheet->calculateWorksheetDimension());
  301. $dimension[0] = PHPExcel_Cell::coordinateFromString($dimension[0]);
  302. $dimension[0][0] = PHPExcel_Cell::columnIndexFromString($dimension[0][0]) - 1;
  303. $dimension[1] = PHPExcel_Cell::coordinateFromString($dimension[1]);
  304. $dimension[1][0] = PHPExcel_Cell::columnIndexFromString($dimension[1][0]) - 1;
  305. // Loop through cells
  306. $rowData = null;
  307. for ($row = $dimension[0][1]; $row <= $dimension[1][1]; ++$row) {
  308. // Start a new row
  309. $rowData = array();
  310. // Loop through columns
  311. for ($column = $dimension[0][0]; $column <= $dimension[1][0]; ++$column) {
  312. // Cell exists?
  313. if ($sheet->cellExistsByColumnAndRow($column, $row)) {
  314. $rowData[$column] = $sheet->getCellByColumnAndRow($column, $row);
  315. } else {
  316. $rowData[$column] = '';
  317. }
  318. }
  319. // Write row if there are HTML table cells in it
  320. if ( !isset($this->_isSpannedRow[$sheet->getParent()->getIndex($sheet)][$row]) ) {
  321. $html .= $this->_generateRow($sheet, $rowData, $row - 1);
  322. }
  323. }
  324. // Write table footer
  325. $html .= $this->_generateTableFooter();
  326. // Writing PDF?
  327. if ($this->_isPdf)
  328. {
  329. if (is_null($this->_sheetIndex) && $sheetId + 1 < $this->_phpExcel->getSheetCount()) {
  330. $html .= '<tcpdf method="AddPage" />';
  331. }
  332. }
  333. // Next sheet
  334. ++$sheetId;
  335. }
  336. // Return
  337. return $html;
  338. }
  339. /**
  340. * Generate image tag in cell
  341. *
  342. * @param PHPExcel_Worksheet $pSheet PHPExcel_Worksheet
  343. * @param string $coordinates Cell coordinates
  344. * @return string
  345. * @throws Exception
  346. */
  347. private function _writeImageTagInCell(PHPExcel_Worksheet $pSheet, $coordinates) {
  348. // Construct HTML
  349. $html = '';
  350. // Write images
  351. foreach ($pSheet->getDrawingCollection() as $drawing) {
  352. if ($drawing instanceof PHPExcel_Worksheet_Drawing) {
  353. if ($drawing->getCoordinates() == $coordinates) {
  354. $filename = $drawing->getPath();
  355. // Strip off eventual '.'
  356. if (substr($filename, 0, 1) == '.') {
  357. $filename = substr($filename, 1);
  358. }
  359. // Prepend images root
  360. $filename = $this->getImagesRoot() . $filename;
  361. // Strip off eventual '.'
  362. if (substr($filename, 0, 1) == '.' && substr($filename, 0, 2) != './') {
  363. $filename = substr($filename, 1);
  364. }
  365. // Convert UTF8 data to PCDATA
  366. $filename = htmlspecialchars($filename);
  367. $html .= "\r\n";
  368. $html .= ' <img style="position: relative; left: ' . $drawing->getOffsetX() . 'px; top: ' . $drawing->getOffsetY() . 'px; width: ' . $drawing->getWidth() . 'px; height: ' . $drawing->getHeight() . 'px;" src="' . $filename . '" border="0" width="' . $drawing->getWidth() . '" height="' . $drawing->getHeight() . '" />' . "\r\n";
  369. }
  370. }
  371. }
  372. // Return
  373. return $html;
  374. }
  375. /**
  376. * Generate CSS styles
  377. *
  378. * @param boolean $generateSurroundingHTML Generate surrounding HTML tags? (<style> and </style>)
  379. * @return string
  380. * @throws Exception
  381. */
  382. public function generateStyles($generateSurroundingHTML = true) {
  383. // PHPExcel object known?
  384. if (is_null($this->_phpExcel)) {
  385. throw new Exception('Internal PHPExcel object not set to an instance of an object.');
  386. }
  387. // Build CSS
  388. $css = $this->buildCSS($generateSurroundingHTML);
  389. // Construct HTML
  390. $html = '';
  391. // Start styles
  392. if ($generateSurroundingHTML) {
  393. $html .= ' <style type="text/css">' . "\r\n";
  394. $html .= ' html { ' . $this->_assembleCSS($css['html']) . ' }' . "\r\n";
  395. }
  396. // Write all other styles
  397. foreach ($css as $styleName => $styleDefinition) {
  398. if ($styleName != 'html') {
  399. $html .= ' ' . $styleName . ' { ' . $this->_assembleCSS($styleDefinition) . ' }' . "\r\n";
  400. }
  401. }
  402. // End styles
  403. if ($generateSurroundingHTML) {
  404. $html .= ' </style>' . "\r\n";
  405. }
  406. // Return
  407. return $html;
  408. }
  409. /**
  410. * Build CSS styles
  411. *
  412. * @param boolean $generateSurroundingHTML Generate surrounding HTML style? (html { })
  413. * @return array
  414. * @throws Exception
  415. */
  416. public function buildCSS($generateSurroundingHTML = true) {
  417. // PHPExcel object known?
  418. if (is_null($this->_phpExcel)) {
  419. throw new Exception('Internal PHPExcel object not set to an instance of an object.');
  420. }
  421. // Cached?
  422. if (!is_null($this->_cssStyles)) {
  423. return $this->_cssStyles;
  424. }
  425. // Ensure that spans have been calculated
  426. if (!$this->_spansAreCalculated) {
  427. $this->_calculateSpans();
  428. }
  429. // Construct CSS
  430. $css = array();
  431. // Start styles
  432. if ($generateSurroundingHTML) {
  433. // html { }
  434. $css['html']['font-family'] = 'Calibri, Arial, Helvetica, sans-serif';
  435. $css['html']['font-size'] = '11pt';
  436. $css['html']['background-color'] = 'white';
  437. }
  438. // table { }
  439. $css['table']['border-collapse'] = 'collapse';
  440. $css['table']['page-break-after'] = 'always';
  441. // .gridlines td { }
  442. $css['.gridlines td']['border'] = '1px dotted black';
  443. // .b {}
  444. $css['.b']['text-align'] = 'center'; // BOOL
  445. // .e {}
  446. $css['.e']['text-align'] = 'center'; // ERROR
  447. // .f {}
  448. $css['.f']['text-align'] = 'right'; // FORMULA
  449. // .inlineStr {}
  450. $css['.inlineStr']['text-align'] = 'left'; // INLINE
  451. // .n {}
  452. $css['.n']['text-align'] = 'right'; // NUMERIC
  453. // .s {}
  454. $css['.s']['text-align'] = 'left'; // STRING
  455. // Calculate cell style hashes
  456. foreach ($this->_phpExcel->getCellXfCollection() as $index => $style) {
  457. $css['td.style' . $index] = $this->_createCSSStyle( $style );
  458. }
  459. // Fetch sheets
  460. $sheets = array();
  461. if (is_null($this->_sheetIndex)) {
  462. $sheets = $this->_phpExcel->getAllSheets();
  463. } else {
  464. $sheets[] = $this->_phpExcel->getSheet($this->_sheetIndex);
  465. }
  466. // Build styles per sheet
  467. foreach ($sheets as $sheet) {
  468. // Calculate hash code
  469. $sheetIndex = $sheet->getParent()->getIndex($sheet);
  470. // Build styles
  471. // Calculate column widths
  472. $sheet->calculateColumnWidths();
  473. // col elements, initialize
  474. $highestColumnIndex = PHPExcel_Cell::columnIndexFromString($sheet->getHighestColumn()) - 1;
  475. for ($column = 0; $column <= $highestColumnIndex; ++$column) {
  476. $this->_columnWidths[$sheetIndex][$column] = 42; // approximation
  477. $css['table.sheet' . $sheetIndex . ' col.col' . $column]['width'] = '42pt';
  478. }
  479. // col elements, loop through columnDimensions and set width
  480. foreach ($sheet->getColumnDimensions() as $columnDimension) {
  481. if (($width = PHPExcel_Shared_Drawing::cellDimensionToPixels($columnDimension->getWidth(), $this->_defaultFont)) >= 0) {
  482. $width = PHPExcel_Shared_Drawing::pixelsToPoints($width);
  483. $column = PHPExcel_Cell::columnIndexFromString($columnDimension->getColumnIndex()) - 1;
  484. $this->_columnWidths[$sheetIndex][$column] = $width;
  485. $css['table.sheet' . $sheetIndex . ' col.col' . $column]['width'] = $width . 'pt';
  486. if ($columnDimension->getVisible() === false) {
  487. $css['table.sheet' . $sheetIndex . ' col.col' . $column]['visibility'] = 'collapse';
  488. $css['table.sheet' . $sheetIndex . ' col.col' . $column]['*display'] = 'none'; // target IE6+7
  489. }
  490. }
  491. }
  492. // Default row height
  493. $rowDimension = $sheet->getDefaultRowDimension();
  494. // table.sheetN tr { }
  495. $css['table.sheet' . $sheetIndex . ' tr'] = array();
  496. if ($rowDimension->getRowHeight() == -1) {
  497. $pt_height = PHPExcel_Shared_Font::getDefaultRowHeightByFont($this->_phpExcel->getDefaultStyle()->getFont());
  498. } else {
  499. $pt_height = $rowDimension->getRowHeight();
  500. }
  501. $css['table.sheet' . $sheetIndex . ' tr']['height'] = $pt_height . 'pt';
  502. if ($rowDimension->getVisible() === false) {
  503. $css['table.sheet' . $sheetIndex . ' tr']['display'] = 'none';
  504. $css['table.sheet' . $sheetIndex . ' tr']['visibility'] = 'hidden';
  505. }
  506. // Calculate row heights
  507. foreach ($sheet->getRowDimensions() as $rowDimension) {
  508. $row = $rowDimension->getRowIndex() - 1;
  509. // table.sheetN tr.rowYYYYYY { }
  510. $css['table.sheet' . $sheetIndex . ' tr.row' . $row] = array();
  511. if ($rowDimension->getRowHeight() == -1) {
  512. $pt_height = PHPExcel_Shared_Font::getDefaultRowHeightByFont($this->_phpExcel->getDefaultStyle()->getFont());
  513. } else {
  514. $pt_height = $rowDimension->getRowHeight();
  515. }
  516. $css['table.sheet' . $sheetIndex . ' tr.row' . $row]['height'] = $pt_height . 'pt';
  517. if ($rowDimension->getVisible() === false) {
  518. $css['table.sheet' . $sheetIndex . ' tr.row' . $row]['display'] = 'none';
  519. $css['table.sheet' . $sheetIndex . ' tr.row' . $row]['visibility'] = 'hidden';
  520. }
  521. }
  522. }
  523. // Cache
  524. if (is_null($this->_cssStyles)) {
  525. $this->_cssStyles = $css;
  526. }
  527. // Return
  528. return $css;
  529. }
  530. /**
  531. * Create CSS style
  532. *
  533. * @param PHPExcel_Style $pStyle PHPExcel_Style
  534. * @return array
  535. */
  536. private function _createCSSStyle(PHPExcel_Style $pStyle) {
  537. // Construct CSS
  538. $css = '';
  539. // Create CSS
  540. $css = array_merge(
  541. $this->_createCSSStyleAlignment($pStyle->getAlignment())
  542. , $this->_createCSSStyleBorders($pStyle->getBorders())
  543. , $this->_createCSSStyleFont($pStyle->getFont())
  544. , $this->_createCSSStyleFill($pStyle->getFill())
  545. );
  546. // Return
  547. return $css;
  548. }
  549. /**
  550. * Create CSS style (PHPExcel_Style_Alignment)
  551. *
  552. * @param PHPExcel_Style_Alignment $pStyle PHPExcel_Style_Alignment
  553. * @return array
  554. */
  555. private function _createCSSStyleAlignment(PHPExcel_Style_Alignment $pStyle) {
  556. // Construct CSS
  557. $css = array();
  558. // Create CSS
  559. $css['vertical-align'] = $this->_mapVAlign($pStyle->getVertical());
  560. if ($textAlign = $this->_mapHAlign($pStyle->getHorizontal())) {
  561. $css['text-align'] = $textAlign;
  562. }
  563. // Return
  564. return $css;
  565. }
  566. /**
  567. * Create CSS style (PHPExcel_Style_Font)
  568. *
  569. * @param PHPExcel_Style_Font $pStyle PHPExcel_Style_Font
  570. * @return array
  571. */
  572. private function _createCSSStyleFont(PHPExcel_Style_Font $pStyle) {
  573. // Construct CSS
  574. $css = array();
  575. // Create CSS
  576. if ($pStyle->getBold()) {
  577. $css['font-weight'] = 'bold';
  578. }
  579. if ($pStyle->getUnderline() != PHPExcel_Style_Font::UNDERLINE_NONE && $pStyle->getStrikethrough()) {
  580. $css['text-decoration'] = 'underline line-through';
  581. } else if ($pStyle->getUnderline() != PHPExcel_Style_Font::UNDERLINE_NONE) {
  582. $css['text-decoration'] = 'underline';
  583. } else if ($pStyle->getStrikethrough()) {
  584. $css['text-decoration'] = 'line-through';
  585. }
  586. if ($pStyle->getItalic()) {
  587. $css['font-style'] = 'italic';
  588. }
  589. $css['color'] = '#' . $pStyle->getColor()->getRGB();
  590. $css['font-family'] = '\'' . $pStyle->getName() . '\'';
  591. $css['font-size'] = $pStyle->getSize() . 'pt';
  592. // Return
  593. return $css;
  594. }
  595. /**
  596. * Create CSS style (PHPExcel_Style_Borders)
  597. *
  598. * @param PHPExcel_Style_Borders $pStyle PHPExcel_Style_Borders
  599. * @return array
  600. */
  601. private function _createCSSStyleBorders(PHPExcel_Style_Borders $pStyle) {
  602. // Construct CSS
  603. $css = array();
  604. // Create CSS
  605. $css['border-bottom'] = $this->_createCSSStyleBorder($pStyle->getBottom());
  606. $css['border-top'] = $this->_createCSSStyleBorder($pStyle->getTop());
  607. $css['border-left'] = $this->_createCSSStyleBorder($pStyle->getLeft());
  608. $css['border-right'] = $this->_createCSSStyleBorder($pStyle->getRight());
  609. // Return
  610. return $css;
  611. }
  612. /**
  613. * Create CSS style (PHPExcel_Style_Border)
  614. *
  615. * @param PHPExcel_Style_Border $pStyle PHPExcel_Style_Border
  616. * @return string
  617. */
  618. private function _createCSSStyleBorder(PHPExcel_Style_Border $pStyle) {
  619. // Construct HTML
  620. $css = '';
  621. // Create CSS
  622. $css .= $this->_mapBorderStyle($pStyle->getBorderStyle()) . ' #' . $pStyle->getColor()->getRGB();
  623. // Return
  624. return $css;
  625. }
  626. /**
  627. * Create CSS style (PHPExcel_Style_Fill)
  628. *
  629. * @param PHPExcel_Style_Fill $pStyle PHPExcel_Style_Fill
  630. * @return array
  631. */
  632. private function _createCSSStyleFill(PHPExcel_Style_Fill $pStyle) {
  633. // Construct HTML
  634. $css = array();
  635. // Create CSS
  636. $value = $pStyle->getFillType() == PHPExcel_Style_Fill::FILL_NONE ?
  637. 'white' : '#' . $pStyle->getStartColor()->getRGB();
  638. $css['background-color'] = $value;
  639. // Return
  640. return $css;
  641. }
  642. /**
  643. * Generate HTML footer
  644. */
  645. public function generateHTMLFooter() {
  646. // Construct HTML
  647. $html = '';
  648. $html .= ' </body>' . "\r\n";
  649. $html .= '</html>' . "\r\n";
  650. // Return
  651. return $html;
  652. }
  653. /**
  654. * Generate table header
  655. *
  656. * @param PHPExcel_Worksheet $pSheet The worksheet for the table we are writing
  657. * @return string
  658. * @throws Exception
  659. */
  660. private function _generateTableHeader($pSheet) {
  661. $sheetIndex = $pSheet->getParent()->getIndex($pSheet);
  662. // Construct HTML
  663. $html = '';
  664. if (!$this->_useInlineCss) {
  665. $gridlines = $pSheet->getShowGridLines() ? ' gridlines' : '';
  666. $html .= ' <table border="0" cellpadding="0" cellspacing="0" class="sheet' . $sheetIndex . $gridlines . '">' . "\r\n";
  667. } else {
  668. $style = isset($this->_cssStyles['table']) ?
  669. $this->_assembleCSS($this->_cssStyles['table']) : '';
  670. $html .= ' <table border="0" cellpadding="0" cellspacing="0" style="' . $style . '">' . "\r\n";
  671. }
  672. // Write <col> elements
  673. $highestColumnIndex = PHPExcel_Cell::columnIndexFromString($pSheet->getHighestColumn()) - 1;
  674. for ($i = 0; $i <= $highestColumnIndex; ++$i) {
  675. if (!$this->_useInlineCss) {
  676. $html .= ' <col class="col' . $i . '">' . "\r\n";
  677. } else {
  678. $style = isset($this->_cssStyles['table.sheet' . $sheetIndex . ' col.col' . $i]) ?
  679. $this->_assembleCSS($this->_cssStyles['table.sheet' . $sheetIndex . ' col.col' . $i]) : '';
  680. $html .= ' <col style="' . $style . '">' . "\r\n";
  681. }
  682. }
  683. // Return
  684. return $html;
  685. }
  686. /**
  687. * Generate table footer
  688. *
  689. * @throws Exception
  690. */
  691. private function _generateTableFooter() {
  692. // Construct HTML
  693. $html = '';
  694. $html .= ' </table>' . "\r\n";
  695. // Return
  696. return $html;
  697. }
  698. /**
  699. * Generate row
  700. *
  701. * @param PHPExcel_Worksheet $pSheet PHPExcel_Worksheet
  702. * @param array $pValues Array containing cells in a row
  703. * @param int $pRow Row number
  704. * @return string
  705. * @throws Exception
  706. */
  707. private function _generateRow(PHPExcel_Worksheet $pSheet, $pValues = null, $pRow = 0) {
  708. if (is_array($pValues)) {
  709. // Construct HTML
  710. $html = '';
  711. // Sheet index
  712. $sheetIndex = $pSheet->getParent()->getIndex($pSheet);
  713. // Write row start
  714. if (!$this->_useInlineCss) {
  715. $html .= ' <tr class="row' . $pRow . '">' . "\r\n";
  716. } else {
  717. $style = isset($this->_cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $pRow])
  718. ? $this->_assembleCSS($this->_cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $pRow]) : '';
  719. $html .= ' <tr style="' . $style . '">' . "\r\n";
  720. }
  721. // Write cells
  722. $colNum = 0;
  723. foreach ($pValues as $cell) {
  724. if (!$this->_useInlineCss) {
  725. $cssClass = '';
  726. $cssClass = 'column' . $colNum;
  727. } else {
  728. $cssClass = array();
  729. if (isset($this->_cssStyles['table.sheet' . $sheetIndex . ' td.column' . $colNum])) {
  730. $this->_cssStyles['table.sheet' . $sheetIndex . ' td.column' . $colNum];
  731. }
  732. }
  733. $colSpan = 1;
  734. $rowSpan = 1;
  735. $writeCell = true; // Write cell
  736. // initialize
  737. $cellData = '';
  738. // PHPExcel_Cell
  739. if ($cell instanceof PHPExcel_Cell) {
  740. // Value
  741. if ($cell->getValue() instanceof PHPExcel_RichText) {
  742. // Loop through rich text elements
  743. $elements = $cell->getValue()->getRichTextElements();
  744. foreach ($elements as $element) {
  745. // Rich text start?
  746. if ($element instanceof PHPExcel_RichText_Run) {
  747. $cellData .= '<span style="' . $this->_assembleCSS($this->_createCSSStyleFont($element->getFont())) . '">';
  748. if ($element->getFont()->getSuperScript()) {
  749. $cellData .= '<sup>';
  750. } else if ($element->getFont()->getSubScript()) {
  751. $cellData .= '<sub>';
  752. }
  753. }
  754. // Convert UTF8 data to PCDATA
  755. $cellText = $element->getText();
  756. $cellData .= htmlspecialchars($cellText);
  757. if ($element instanceof PHPExcel_RichText_Run) {
  758. if ($element->getFont()->getSuperScript()) {
  759. $cellData .= '</sup>';
  760. } else if ($element->getFont()->getSubScript()) {
  761. $cellData .= '</sub>';
  762. }
  763. $cellData .= '</span>';
  764. }
  765. }
  766. } else {
  767. if ($this->_preCalculateFormulas) {
  768. $cellData = PHPExcel_Style_NumberFormat::toFormattedString(
  769. $cell->getCalculatedValue(),
  770. $pSheet->getParent()->getCellXfByIndex( $cell->getXfIndex() )->getNumberFormat()->getFormatCode(),
  771. array($this, 'formatColor')
  772. );
  773. } else {
  774. $cellData = PHPExcel_Style_NumberFormat::ToFormattedString(
  775. $cell->getValue(),
  776. $pSheet->getParent()->getCellXfByIndex( $cell->getXfIndex() )->getNumberFormat()->getFormatCode(),
  777. array($this, 'formatColor')
  778. );
  779. }
  780. }
  781. // replace leading spaces on each line with &nbsp;
  782. $cellData = $this->_convertNbsp($cellData);
  783. // convert newline "\n" to '<br>'
  784. $cellData = str_replace("\n", '<br/>', $cellData);
  785. // Check value
  786. if ($cellData == '') {
  787. $cellData = '&nbsp;';
  788. }
  789. // Extend CSS class?
  790. if (!$this->_useInlineCss) {
  791. $cssClass .= ' style' . $cell->getXfIndex();
  792. $cssClass .= ' ' . $cell->getDataType();
  793. } else {
  794. if (isset($this->_cssStyles['td.style' . $cell->getXfIndex()])) {
  795. $cssClass = array_merge($cssClass, $this->_cssStyles['td.style' . $cell->getXfIndex()]);
  796. }
  797. // General horizontal alignment: Actual horizontal alignment depends on dataType
  798. $sharedStyle = $pSheet->getParent()->getCellXfByIndex( $cell->getXfIndex() );
  799. if ($sharedStyle->getAlignment()->getHorizontal() == PHPExcel_Style_Alignment::HORIZONTAL_GENERAL
  800. && isset($this->_cssStyles['.' . $cell->getDataType()]['text-align']))
  801. {
  802. $cssClass['text-align'] = $this->_cssStyles['.' . $cell->getDataType()]['text-align'];
  803. }
  804. }
  805. } else {
  806. $cell = new PHPExcel_Cell(
  807. PHPExcel_Cell::stringFromColumnIndex($colNum),
  808. ($pRow + 1),
  809. '',
  810. PHPExcel_Cell_DataType::TYPE_NULL,
  811. $pSheet
  812. );
  813. }
  814. // Hyperlink?
  815. if ($cell->hasHyperlink() && !$cell->getHyperlink()->isInternal()) {
  816. $cellData = '<a href="' . htmlspecialchars($cell->getHyperlink()->getUrl()) . '" title="' . htmlspecialchars($cell->getHyperlink()->getTooltip()) . '">' . $cellData . '</a>';
  817. }
  818. // Should the cell be written or is it swallowed by a rowspan or colspan?
  819. $writeCell = ! ( isset($this->_isSpannedCell[$pSheet->getParent()->getIndex($pSheet)][$pRow + 1][$colNum])
  820. && $this->_isSpannedCell[$pSheet->getParent()->getIndex($pSheet)][$pRow + 1][$colNum] );
  821. // Colspan and Rowspan
  822. $colspan = 1;
  823. $rowspan = 1;
  824. if (isset($this->_isBaseCell[$pSheet->getParent()->getIndex($pSheet)][$pRow + 1][$colNum])) {
  825. $spans = $this->_isBaseCell[$pSheet->getParent()->getIndex($pSheet)][$pRow + 1][$colNum];
  826. $rowSpan = $spans['rowspan'];
  827. $colSpan = $spans['colspan'];
  828. }
  829. // Write
  830. if ($writeCell) {
  831. // Column start
  832. $html .= ' <td';
  833. if (!$this->_useInlineCss) {
  834. $html .= ' class="' . $cssClass . '"';
  835. } else {
  836. //** Necessary redundant code for the sake of PHPExcel_Writer_PDF **
  837. // We must explicitly write the width of the <td> element because TCPDF
  838. // does not recognize e.g. <col style="width:42pt">
  839. $width = 0;
  840. $columnIndex = PHPExcel_Cell::columnIndexFromString($cell->getColumn()) - 1;
  841. for ($i = $columnIndex; $i < $columnIndex + $colSpan; ++$i) {
  842. if (isset($this->_columnWidths[$sheetIndex][$i])) {
  843. $width += $this->_columnWidths[$sheetIndex][$i];
  844. }
  845. }
  846. $cssClass['width'] = $width . 'pt';
  847. // We must also explicitly write the height of the <td> element because TCPDF
  848. // does not recognize e.g. <tr style="height:50pt">
  849. if (isset($this->_cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $pRow]['height'])) {
  850. $height = $this->_cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $pRow]['height'];
  851. $cssClass['height'] = $height;
  852. }
  853. //** end of redundant code **
  854. $html .= ' style="' . $this->_assembleCSS($cssClass) . '"';
  855. }
  856. if ($colSpan > 1) {
  857. $html .= ' colspan="' . $colSpan . '"';
  858. }
  859. if ($rowSpan > 1) {
  860. $html .= ' rowspan="' . $rowSpan . '"';
  861. }
  862. $html .= '>';
  863. // Image?
  864. $html .= $this->_writeImageTagInCell($pSheet, $cell->getCoordinate());
  865. // Cell data
  866. $html .= $cellData;
  867. // Column end
  868. $html .= '</td>' . "\r\n";
  869. }
  870. // Next column
  871. ++$colNum;
  872. }
  873. // Write row end
  874. $html .= ' </tr>' . "\r\n";
  875. // Return
  876. return $html;
  877. } else {
  878. throw new Exception("Invalid parameters passed.");
  879. }
  880. }
  881. /**
  882. * Takes array where of CSS properties / values and converts to CSS string
  883. *
  884. * @param array
  885. * @return string
  886. */
  887. private function _assembleCSS($pValue = array())
  888. {
  889. $pairs = array();
  890. foreach ($pValue as $property => $value) {
  891. $pairs[] = $property . ':' . $value;
  892. }
  893. $string = implode('; ', $pairs);
  894. return $string;
  895. }
  896. /**
  897. * Get Pre-Calculate Formulas
  898. *
  899. * @return boolean
  900. */
  901. public function getPreCalculateFormulas() {
  902. return $this->_preCalculateFormulas;
  903. }
  904. /**
  905. * Set Pre-Calculate Formulas
  906. *
  907. * @param boolean $pValue Pre-Calculate Formulas?
  908. * @return PHPExcel_Writer_HTML
  909. */
  910. public function setPreCalculateFormulas($pValue = true) {
  911. $this->_preCalculateFormulas = $pValue;
  912. return $this;
  913. }
  914. /**
  915. * Get images root
  916. *
  917. * @return string
  918. */
  919. public function getImagesRoot() {
  920. return $this->_imagesRoot;
  921. }
  922. /**
  923. * Set images root
  924. *
  925. * @param string $pValue
  926. * @return PHPExcel_Writer_HTML
  927. */
  928. public function setImagesRoot($pValue = '.') {
  929. $this->_imagesRoot = $pValue;
  930. return $this;
  931. }
  932. /**
  933. * Get use inline CSS?
  934. *
  935. * @return boolean
  936. */
  937. public function getUseInlineCss() {
  938. return $this->_useInlineCss;
  939. }
  940. /**
  941. * Set use inline CSS?
  942. *
  943. * @param boolean $pValue
  944. * @return PHPExcel_Writer_HTML
  945. */
  946. public function setUseInlineCss($pValue = false) {
  947. $this->_useInlineCss = $pValue;
  948. return $this;
  949. }
  950. /**
  951. * Converts a string so that spaces occuring at beginning of each new line are replaced by &nbsp;
  952. * Example: " Hello\n to the world" is converted to "&nbsp;&nbsp;Hello\n&nbsp;to the world"
  953. *
  954. * @param string $pValue
  955. * @return string
  956. */
  957. private function _convertNbsp($pValue = '')
  958. {
  959. $explodes = explode("\n", $pValue);
  960. foreach ($explodes as $explode) {
  961. $matches = array();
  962. if (preg_match('/^( )+/', $explode, $matches)) {
  963. $explode = str_repeat('&nbsp;', strlen($matches[0])) . substr($explode, strlen($matches[0]));
  964. }
  965. $implodes[] = $explode;
  966. }
  967. $string = implode("\n", $implodes);
  968. return $string;
  969. }
  970. /**
  971. * Add color to formatted string as inline style
  972. *
  973. * @param string $pValue Plain formatted value without color
  974. * @param string $pFormat Format code
  975. * @return string
  976. */
  977. public function formatColor($pValue, $pFormat)
  978. {
  979. // Color information, e.g. [Red] is always at the beginning
  980. $color = null; // initialize
  981. $matches = array();
  982. $color_regex = '/^\\[[a-zA-Z]+\\]/';
  983. if (preg_match($color_regex, $pFormat, $matches)) {
  984. $color = str_replace('[', '', $matches[0]);
  985. $color = str_replace(']', '', $color);
  986. $color = strtolower($color);
  987. }
  988. // convert to PCDATA
  989. $value = htmlspecialchars($pValue);
  990. // color span tag
  991. if ($color !== null) {
  992. $value = '<span style="color:' . $color . '">' . $value . '</span>';
  993. }
  994. return $value;
  995. }
  996. /**
  997. * Calculate information about HTML colspan and rowspan which is not always the same as Excel's
  998. */
  999. private function _calculateSpans()
  1000. {
  1001. // Identify all cells that should be omitted in HTML due to cell merge.
  1002. // In HTML only the upper-left cell should be written and it should have
  1003. // appropriate rowspan / colspan attribute
  1004. $sheetIndexes = $this->_sheetIndex !== null ?
  1005. array($this->_sheetIndex) : range(0, $this->_phpExcel->getSheetCount() - 1);
  1006. foreach ($sheetIndexes as $sheetIndex) {
  1007. $sheet = $this->_phpExcel->getSheet($sheetIndex);
  1008. $candidateSpannedRow = array();
  1009. // loop through all Excel merged cells
  1010. foreach ($sheet->getMergeCells() as $cells) {
  1011. list($cells, ) = PHPExcel_Cell::splitRange($cells);
  1012. $first = $cells[0];
  1013. $last = $cells[1];
  1014. list($fc, $fr) = PHPExcel_Cell::coordinateFromString($first);
  1015. $fc = PHPExcel_Cell::columnIndexFromString($fc) - 1;
  1016. list($lc, $lr) = PHPExcel_Cell::coordinateFromString($last);
  1017. $lc = PHPExcel_Cell::columnIndexFromString($lc) - 1;
  1018. // loop through the individual cells in the individual merge
  1019. for ($r = $fr; $r <= $lr; ++$r) {
  1020. // also, flag this row as a HTML row that is candidate to be omitted
  1021. $candidateSpannedRow[$r] = $r;
  1022. for ($c = $fc; $c <= $lc; ++$c) {
  1023. if ( !($c == $fc && $r == $fr) ) {
  1024. // not the upper-left cell (should not be written in HTML)
  1025. $this->_isSpannedCell[$sheetIndex][$r][$c] = array(
  1026. 'baseCell' => array($fr, $fc),
  1027. );
  1028. } else {
  1029. // upper-left is the base cell that should hold the colspan/rowspan attribute
  1030. $this->_isBaseCell[$sheetIndex][$r][$c] = array(
  1031. 'xlrowspan' => $lr - $fr + 1, // Excel rowspan
  1032. 'rowspan' => $lr - $fr + 1, // HTML rowspan, value may change
  1033. 'xlcolspan' => $lc - $fc + 1, // Excel colspan
  1034. 'colspan' => $lc - $fc + 1, // HTML colspan, value may change
  1035. );
  1036. }
  1037. }
  1038. }
  1039. }
  1040. // Identify which rows should be omitted in HTML. These are the rows where all the cells
  1041. // participate in a merge and the where base cells are somewhere above.
  1042. $countColumns = PHPExcel_Cell::columnIndexFromString($sheet->getHighestColumn());
  1043. foreach ($candidateSpannedRow as $rowIndex) {
  1044. if (isset($this->_isSpannedCell[$sheetIndex][$rowIndex])) {
  1045. if (count($this->_isSpannedCell[$sheetIndex][$rowIndex]) == $countColumns) {
  1046. $this->_isSpannedRow[$sheetIndex][$rowIndex] = $rowIndex;
  1047. };
  1048. }
  1049. }
  1050. // For each of the omitted rows we found above, the affected rowspans should be subtracted by 1
  1051. if ( isset($this->_isSpannedRow[$sheetIndex]) ) {
  1052. foreach ($this->_isSpannedRow[$sheetIndex] as $rowIndex) {
  1053. $adjustedBaseCells = array();
  1054. for ($c = 0; $c < $countColumns; ++$c) {
  1055. $baseCell = $this->_isSpannedCell[$sheetIndex][$rowIndex][$c]['baseCell'];
  1056. if ( !in_array($baseCell, $adjustedBaseCells) ) {
  1057. // subtract rowspan by 1
  1058. --$this->_isBaseCell[$sheetIndex][ $baseCell[0] ][ $baseCell[1] ]['rowspan'];
  1059. $adjustedBaseCells[] = $baseCell;
  1060. }
  1061. }
  1062. }
  1063. }
  1064. // TODO: Same for columns
  1065. }
  1066. // We have calculated the spans
  1067. $this->_spansAreCalculated = true;
  1068. }
  1069. }