[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * PHPExcel_Writer_HTML 5 * 6 * Copyright (c) 2006 - 2015 PHPExcel 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 * @category PHPExcel 23 * @package PHPExcel_Writer_HTML 24 * @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) 25 * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL 26 * @version ##VERSION##, ##DATE## 27 */ 28 class PHPExcel_Writer_HTML extends PHPExcel_Writer_Abstract implements PHPExcel_Writer_IWriter 29 { 30 /** 31 * PHPExcel object 32 * 33 * @var PHPExcel 34 */ 35 protected $phpExcel; 36 37 /** 38 * Sheet index to write 39 * 40 * @var int 41 */ 42 private $sheetIndex = 0; 43 44 /** 45 * Images root 46 * 47 * @var string 48 */ 49 private $imagesRoot = '.'; 50 51 /** 52 * embed images, or link to images 53 * 54 * @var boolean 55 */ 56 private $embedImages = false; 57 58 /** 59 * Use inline CSS? 60 * 61 * @var boolean 62 */ 63 private $useInlineCss = false; 64 65 /** 66 * Array of CSS styles 67 * 68 * @var array 69 */ 70 private $cssStyles; 71 72 /** 73 * Array of column widths in points 74 * 75 * @var array 76 */ 77 private $columnWidths; 78 79 /** 80 * Default font 81 * 82 * @var PHPExcel_Style_Font 83 */ 84 private $defaultFont; 85 86 /** 87 * Flag whether spans have been calculated 88 * 89 * @var boolean 90 */ 91 private $spansAreCalculated = false; 92 93 /** 94 * Excel cells that should not be written as HTML cells 95 * 96 * @var array 97 */ 98 private $isSpannedCell = array(); 99 100 /** 101 * Excel cells that are upper-left corner in a cell merge 102 * 103 * @var array 104 */ 105 private $isBaseCell = array(); 106 107 /** 108 * Excel rows that should not be written as HTML rows 109 * 110 * @var array 111 */ 112 private $isSpannedRow = array(); 113 114 /** 115 * Is the current writer creating PDF? 116 * 117 * @var boolean 118 */ 119 protected $isPdf = false; 120 121 /** 122 * Generate the Navigation block 123 * 124 * @var boolean 125 */ 126 private $generateSheetNavigationBlock = true; 127 128 /** 129 * Create a new PHPExcel_Writer_HTML 130 * 131 * @param PHPExcel $phpExcel PHPExcel object 132 */ 133 public function __construct(PHPExcel $phpExcel) 134 { 135 $this->phpExcel = $phpExcel; 136 $this->defaultFont = $this->phpExcel->getDefaultStyle()->getFont(); 137 } 138 139 /** 140 * Save PHPExcel to file 141 * 142 * @param string $pFilename 143 * @throws PHPExcel_Writer_Exception 144 */ 145 public function save($pFilename = null) 146 { 147 // garbage collect 148 $this->phpExcel->garbageCollect(); 149 150 $saveDebugLog = PHPExcel_Calculation::getInstance($this->phpExcel)->getDebugLog()->getWriteDebugLog(); 151 PHPExcel_Calculation::getInstance($this->phpExcel)->getDebugLog()->setWriteDebugLog(false); 152 $saveArrayReturnType = PHPExcel_Calculation::getArrayReturnType(); 153 PHPExcel_Calculation::setArrayReturnType(PHPExcel_Calculation::RETURN_ARRAY_AS_VALUE); 154 155 // Build CSS 156 $this->buildCSS(!$this->useInlineCss); 157 158 // Open file 159 $fileHandle = fopen($pFilename, 'wb+'); 160 if ($fileHandle === false) { 161 throw new PHPExcel_Writer_Exception("Could not open file $pFilename for writing."); 162 } 163 164 // Write headers 165 fwrite($fileHandle, $this->generateHTMLHeader(!$this->useInlineCss)); 166 167 // Write navigation (tabs) 168 if ((!$this->isPdf) && ($this->generateSheetNavigationBlock)) { 169 fwrite($fileHandle, $this->generateNavigation()); 170 } 171 172 // Write data 173 fwrite($fileHandle, $this->generateSheetData()); 174 175 // Write footer 176 fwrite($fileHandle, $this->generateHTMLFooter()); 177 178 // Close file 179 fclose($fileHandle); 180 181 PHPExcel_Calculation::setArrayReturnType($saveArrayReturnType); 182 PHPExcel_Calculation::getInstance($this->phpExcel)->getDebugLog()->setWriteDebugLog($saveDebugLog); 183 } 184 185 /** 186 * Map VAlign 187 * 188 * @param string $vAlign Vertical alignment 189 * @return string 190 */ 191 private function mapVAlign($vAlign) 192 { 193 switch ($vAlign) { 194 case PHPExcel_Style_Alignment::VERTICAL_BOTTOM: 195 return 'bottom'; 196 case PHPExcel_Style_Alignment::VERTICAL_TOP: 197 return 'top'; 198 case PHPExcel_Style_Alignment::VERTICAL_CENTER: 199 case PHPExcel_Style_Alignment::VERTICAL_JUSTIFY: 200 return 'middle'; 201 default: 202 return 'baseline'; 203 } 204 } 205 206 /** 207 * Map HAlign 208 * 209 * @param string $hAlign Horizontal alignment 210 * @return string|false 211 */ 212 private function mapHAlign($hAlign) 213 { 214 switch ($hAlign) { 215 case PHPExcel_Style_Alignment::HORIZONTAL_GENERAL: 216 return false; 217 case PHPExcel_Style_Alignment::HORIZONTAL_LEFT: 218 return 'left'; 219 case PHPExcel_Style_Alignment::HORIZONTAL_RIGHT: 220 return 'right'; 221 case PHPExcel_Style_Alignment::HORIZONTAL_CENTER: 222 case PHPExcel_Style_Alignment::HORIZONTAL_CENTER_CONTINUOUS: 223 return 'center'; 224 case PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY: 225 return 'justify'; 226 default: 227 return false; 228 } 229 } 230 231 /** 232 * Map border style 233 * 234 * @param int $borderStyle Sheet index 235 * @return string 236 */ 237 private function mapBorderStyle($borderStyle) 238 { 239 switch ($borderStyle) { 240 case PHPExcel_Style_Border::BORDER_NONE: 241 return 'none'; 242 case PHPExcel_Style_Border::BORDER_DASHDOT: 243 return '1px dashed'; 244 case PHPExcel_Style_Border::BORDER_DASHDOTDOT: 245 return '1px dotted'; 246 case PHPExcel_Style_Border::BORDER_DASHED: 247 return '1px dashed'; 248 case PHPExcel_Style_Border::BORDER_DOTTED: 249 return '1px dotted'; 250 case PHPExcel_Style_Border::BORDER_DOUBLE: 251 return '3px double'; 252 case PHPExcel_Style_Border::BORDER_HAIR: 253 return '1px solid'; 254 case PHPExcel_Style_Border::BORDER_MEDIUM: 255 return '2px solid'; 256 case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT: 257 return '2px dashed'; 258 case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT: 259 return '2px dotted'; 260 case PHPExcel_Style_Border::BORDER_MEDIUMDASHED: 261 return '2px dashed'; 262 case PHPExcel_Style_Border::BORDER_SLANTDASHDOT: 263 return '2px dashed'; 264 case PHPExcel_Style_Border::BORDER_THICK: 265 return '3px solid'; 266 case PHPExcel_Style_Border::BORDER_THIN: 267 return '1px solid'; 268 default: 269 // map others to thin 270 return '1px solid'; 271 } 272 } 273 274 /** 275 * Get sheet index 276 * 277 * @return int 278 */ 279 public function getSheetIndex() 280 { 281 return $this->sheetIndex; 282 } 283 284 /** 285 * Set sheet index 286 * 287 * @param int $pValue Sheet index 288 * @return PHPExcel_Writer_HTML 289 */ 290 public function setSheetIndex($pValue = 0) 291 { 292 $this->sheetIndex = $pValue; 293 return $this; 294 } 295 296 /** 297 * Get sheet index 298 * 299 * @return boolean 300 */ 301 public function getGenerateSheetNavigationBlock() 302 { 303 return $this->generateSheetNavigationBlock; 304 } 305 306 /** 307 * Set sheet index 308 * 309 * @param boolean $pValue Flag indicating whether the sheet navigation block should be generated or not 310 * @return PHPExcel_Writer_HTML 311 */ 312 public function setGenerateSheetNavigationBlock($pValue = true) 313 { 314 $this->generateSheetNavigationBlock = (bool) $pValue; 315 return $this; 316 } 317 318 /** 319 * Write all sheets (resets sheetIndex to NULL) 320 */ 321 public function writeAllSheets() 322 { 323 $this->sheetIndex = null; 324 return $this; 325 } 326 327 /** 328 * Generate HTML header 329 * 330 * @param boolean $pIncludeStyles Include styles? 331 * @return string 332 * @throws PHPExcel_Writer_Exception 333 */ 334 public function generateHTMLHeader($pIncludeStyles = false) 335 { 336 // PHPExcel object known? 337 if (is_null($this->phpExcel)) { 338 throw new PHPExcel_Writer_Exception('Internal PHPExcel object not set to an instance of an object.'); 339 } 340 341 // Construct HTML 342 $properties = $this->phpExcel->getProperties(); 343 $html = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">' . PHP_EOL; 344 $html .= '<!-- Generated by PHPExcel - http://www.phpexcel.net -->' . PHP_EOL; 345 $html .= '<html>' . PHP_EOL; 346 $html .= ' <head>' . PHP_EOL; 347 $html .= ' <meta http-equiv="Content-Type" content="text/html; charset=utf-8">' . PHP_EOL; 348 if ($properties->getTitle() > '') { 349 $html .= ' <title>' . htmlspecialchars($properties->getTitle()) . '</title>' . PHP_EOL; 350 } 351 if ($properties->getCreator() > '') { 352 $html .= ' <meta name="author" content="' . htmlspecialchars($properties->getCreator()) . '" />' . PHP_EOL; 353 } 354 if ($properties->getTitle() > '') { 355 $html .= ' <meta name="title" content="' . htmlspecialchars($properties->getTitle()) . '" />' . PHP_EOL; 356 } 357 if ($properties->getDescription() > '') { 358 $html .= ' <meta name="description" content="' . htmlspecialchars($properties->getDescription()) . '" />' . PHP_EOL; 359 } 360 if ($properties->getSubject() > '') { 361 $html .= ' <meta name="subject" content="' . htmlspecialchars($properties->getSubject()) . '" />' . PHP_EOL; 362 } 363 if ($properties->getKeywords() > '') { 364 $html .= ' <meta name="keywords" content="' . htmlspecialchars($properties->getKeywords()) . '" />' . PHP_EOL; 365 } 366 if ($properties->getCategory() > '') { 367 $html .= ' <meta name="category" content="' . htmlspecialchars($properties->getCategory()) . '" />' . PHP_EOL; 368 } 369 if ($properties->getCompany() > '') { 370 $html .= ' <meta name="company" content="' . htmlspecialchars($properties->getCompany()) . '" />' . PHP_EOL; 371 } 372 if ($properties->getManager() > '') { 373 $html .= ' <meta name="manager" content="' . htmlspecialchars($properties->getManager()) . '" />' . PHP_EOL; 374 } 375 376 if ($pIncludeStyles) { 377 $html .= $this->generateStyles(true); 378 } 379 380 $html .= ' </head>' . PHP_EOL; 381 $html .= '' . PHP_EOL; 382 $html .= ' <body>' . PHP_EOL; 383 384 return $html; 385 } 386 387 /** 388 * Generate sheet data 389 * 390 * @return string 391 * @throws PHPExcel_Writer_Exception 392 */ 393 public function generateSheetData() 394 { 395 // PHPExcel object known? 396 if (is_null($this->phpExcel)) { 397 throw new PHPExcel_Writer_Exception('Internal PHPExcel object not set to an instance of an object.'); 398 } 399 400 // Ensure that Spans have been calculated? 401 if (!$this->spansAreCalculated) { 402 $this->calculateSpans(); 403 } 404 405 // Fetch sheets 406 $sheets = array(); 407 if (is_null($this->sheetIndex)) { 408 $sheets = $this->phpExcel->getAllSheets(); 409 } else { 410 $sheets[] = $this->phpExcel->getSheet($this->sheetIndex); 411 } 412 413 // Construct HTML 414 $html = ''; 415 416 // Loop all sheets 417 $sheetId = 0; 418 foreach ($sheets as $sheet) { 419 // Write table header 420 $html .= $this->generateTableHeader($sheet); 421 422 // Get worksheet dimension 423 $dimension = explode(':', $sheet->calculateWorksheetDimension()); 424 $dimension[0] = PHPExcel_Cell::coordinateFromString($dimension[0]); 425 $dimension[0][0] = PHPExcel_Cell::columnIndexFromString($dimension[0][0]) - 1; 426 $dimension[1] = PHPExcel_Cell::coordinateFromString($dimension[1]); 427 $dimension[1][0] = PHPExcel_Cell::columnIndexFromString($dimension[1][0]) - 1; 428 429 // row min,max 430 $rowMin = $dimension[0][1]; 431 $rowMax = $dimension[1][1]; 432 433 // calculate start of <tbody>, <thead> 434 $tbodyStart = $rowMin; 435 $theadStart = $theadEnd = 0; // default: no <thead> no </thead> 436 if ($sheet->getPageSetup()->isRowsToRepeatAtTopSet()) { 437 $rowsToRepeatAtTop = $sheet->getPageSetup()->getRowsToRepeatAtTop(); 438 439 // we can only support repeating rows that start at top row 440 if ($rowsToRepeatAtTop[0] == 1) { 441 $theadStart = $rowsToRepeatAtTop[0]; 442 $theadEnd = $rowsToRepeatAtTop[1]; 443 $tbodyStart = $rowsToRepeatAtTop[1] + 1; 444 } 445 } 446 447 // Loop through cells 448 $row = $rowMin-1; 449 while ($row++ < $rowMax) { 450 // <thead> ? 451 if ($row == $theadStart) { 452 $html .= ' <thead>' . PHP_EOL; 453 $cellType = 'th'; 454 } 455 456 // <tbody> ? 457 if ($row == $tbodyStart) { 458 $html .= ' <tbody>' . PHP_EOL; 459 $cellType = 'td'; 460 } 461 462 // Write row if there are HTML table cells in it 463 if (!isset($this->isSpannedRow[$sheet->getParent()->getIndex($sheet)][$row])) { 464 // Start a new rowData 465 $rowData = array(); 466 // Loop through columns 467 $column = $dimension[0][0] - 1; 468 while ($column++ < $dimension[1][0]) { 469 // Cell exists? 470 if ($sheet->cellExistsByColumnAndRow($column, $row)) { 471 $rowData[$column] = PHPExcel_Cell::stringFromColumnIndex($column) . $row; 472 } else { 473 $rowData[$column] = ''; 474 } 475 } 476 $html .= $this->generateRow($sheet, $rowData, $row - 1, $cellType); 477 } 478 479 // </thead> ? 480 if ($row == $theadEnd) { 481 $html .= ' </thead>' . PHP_EOL; 482 } 483 } 484 $html .= $this->extendRowsForChartsAndImages($sheet, $row); 485 486 // Close table body. 487 $html .= ' </tbody>' . PHP_EOL; 488 489 // Write table footer 490 $html .= $this->generateTableFooter(); 491 492 // Writing PDF? 493 if ($this->isPdf) { 494 if (is_null($this->sheetIndex) && $sheetId + 1 < $this->phpExcel->getSheetCount()) { 495 $html .= '<div style="page-break-before:always" />'; 496 } 497 } 498 499 // Next sheet 500 ++$sheetId; 501 } 502 503 return $html; 504 } 505 506 /** 507 * Generate sheet tabs 508 * 509 * @return string 510 * @throws PHPExcel_Writer_Exception 511 */ 512 public function generateNavigation() 513 { 514 // PHPExcel object known? 515 if (is_null($this->phpExcel)) { 516 throw new PHPExcel_Writer_Exception('Internal PHPExcel object not set to an instance of an object.'); 517 } 518 519 // Fetch sheets 520 $sheets = array(); 521 if (is_null($this->sheetIndex)) { 522 $sheets = $this->phpExcel->getAllSheets(); 523 } else { 524 $sheets[] = $this->phpExcel->getSheet($this->sheetIndex); 525 } 526 527 // Construct HTML 528 $html = ''; 529 530 // Only if there are more than 1 sheets 531 if (count($sheets) > 1) { 532 // Loop all sheets 533 $sheetId = 0; 534 535 $html .= '<ul class="navigation">' . PHP_EOL; 536 537 foreach ($sheets as $sheet) { 538 $html .= ' <li class="sheet' . $sheetId . '"><a href="#sheet' . $sheetId . '">' . $sheet->getTitle() . '</a></li>' . PHP_EOL; 539 ++$sheetId; 540 } 541 542 $html .= '</ul>' . PHP_EOL; 543 } 544 545 return $html; 546 } 547 548 private function extendRowsForChartsAndImages(PHPExcel_Worksheet $pSheet, $row) 549 { 550 $rowMax = $row; 551 $colMax = 'A'; 552 if ($this->includeCharts) { 553 foreach ($pSheet->getChartCollection() as $chart) { 554 if ($chart instanceof PHPExcel_Chart) { 555 $chartCoordinates = $chart->getTopLeftPosition(); 556 $chartTL = PHPExcel_Cell::coordinateFromString($chartCoordinates['cell']); 557 $chartCol = PHPExcel_Cell::columnIndexFromString($chartTL[0]); 558 if ($chartTL[1] > $rowMax) { 559 $rowMax = $chartTL[1]; 560 if ($chartCol > PHPExcel_Cell::columnIndexFromString($colMax)) { 561 $colMax = $chartTL[0]; 562 } 563 } 564 } 565 } 566 } 567 568 foreach ($pSheet->getDrawingCollection() as $drawing) { 569 if ($drawing instanceof PHPExcel_Worksheet_Drawing) { 570 $imageTL = PHPExcel_Cell::coordinateFromString($drawing->getCoordinates()); 571 $imageCol = PHPExcel_Cell::columnIndexFromString($imageTL[0]); 572 if ($imageTL[1] > $rowMax) { 573 $rowMax = $imageTL[1]; 574 if ($imageCol > PHPExcel_Cell::columnIndexFromString($colMax)) { 575 $colMax = $imageTL[0]; 576 } 577 } 578 } 579 } 580 581 $html = ''; 582 $colMax++; 583 while ($row <= $rowMax) { 584 $html .= '<tr>'; 585 for ($col = 'A'; $col != $colMax; ++$col) { 586 $html .= '<td>'; 587 $html .= $this->writeImageInCell($pSheet, $col.$row); 588 if ($this->includeCharts) { 589 $html .= $this->writeChartInCell($pSheet, $col.$row); 590 } 591 $html .= '</td>'; 592 } 593 ++$row; 594 $html .= '</tr>'; 595 } 596 return $html; 597 } 598 599 600 /** 601 * Generate image tag in cell 602 * 603 * @param PHPExcel_Worksheet $pSheet PHPExcel_Worksheet 604 * @param string $coordinates Cell coordinates 605 * @return string 606 * @throws PHPExcel_Writer_Exception 607 */ 608 private function writeImageInCell(PHPExcel_Worksheet $pSheet, $coordinates) 609 { 610 // Construct HTML 611 $html = ''; 612 613 // Write images 614 foreach ($pSheet->getDrawingCollection() as $drawing) { 615 if ($drawing instanceof PHPExcel_Worksheet_Drawing) { 616 if ($drawing->getCoordinates() == $coordinates) { 617 $filename = $drawing->getPath(); 618 619 // Strip off eventual '.' 620 if (substr($filename, 0, 1) == '.') { 621 $filename = substr($filename, 1); 622 } 623 624 // Prepend images root 625 $filename = $this->getImagesRoot() . $filename; 626 627 // Strip off eventual '.' 628 if (substr($filename, 0, 1) == '.' && substr($filename, 0, 2) != './') { 629 $filename = substr($filename, 1); 630 } 631 632 // Convert UTF8 data to PCDATA 633 $filename = htmlspecialchars($filename); 634 635 $html .= PHP_EOL; 636 if ((!$this->embedImages) || ($this->isPdf)) { 637 $imageData = $filename; 638 } else { 639 $imageDetails = getimagesize($filename); 640 if ($fp = fopen($filename, "rb", 0)) { 641 $picture = fread($fp, filesize($filename)); 642 fclose($fp); 643 // base64 encode the binary data, then break it 644 // into chunks according to RFC 2045 semantics 645 $base64 = chunk_split(base64_encode($picture)); 646 $imageData = 'data:'.$imageDetails['mime'].';base64,' . $base64; 647 } else { 648 $imageData = $filename; 649 } 650 } 651 652 $html .= '<div style="position: relative;">'; 653 $html .= '<img style="position: absolute; z-index: 1; left: ' . 654 $drawing->getOffsetX() . 'px; top: ' . $drawing->getOffsetY() . 'px; width: ' . 655 $drawing->getWidth() . 'px; height: ' . $drawing->getHeight() . 'px;" src="' . 656 $imageData . '" border="0" />'; 657 $html .= '</div>'; 658 } 659 } 660 } 661 662 return $html; 663 } 664 665 /** 666 * Generate chart tag in cell 667 * 668 * @param PHPExcel_Worksheet $pSheet PHPExcel_Worksheet 669 * @param string $coordinates Cell coordinates 670 * @return string 671 * @throws PHPExcel_Writer_Exception 672 */ 673 private function writeChartInCell(PHPExcel_Worksheet $pSheet, $coordinates) 674 { 675 // Construct HTML 676 $html = ''; 677 678 // Write charts 679 foreach ($pSheet->getChartCollection() as $chart) { 680 if ($chart instanceof PHPExcel_Chart) { 681 $chartCoordinates = $chart->getTopLeftPosition(); 682 if ($chartCoordinates['cell'] == $coordinates) { 683 $chartFileName = PHPExcel_Shared_File::sys_get_temp_dir().'/'.uniqid().'.png'; 684 if (!$chart->render($chartFileName)) { 685 return; 686 } 687 688 $html .= PHP_EOL; 689 $imageDetails = getimagesize($chartFileName); 690 if ($fp = fopen($chartFileName, "rb", 0)) { 691 $picture = fread($fp, filesize($chartFileName)); 692 fclose($fp); 693 // base64 encode the binary data, then break it 694 // into chunks according to RFC 2045 semantics 695 $base64 = chunk_split(base64_encode($picture)); 696 $imageData = 'data:'.$imageDetails['mime'].';base64,' . $base64; 697 698 $html .= '<div style="position: relative;">'; 699 $html .= '<img style="position: absolute; z-index: 1; left: ' . $chartCoordinates['xOffset'] . 'px; top: ' . $chartCoordinates['yOffset'] . 'px; width: ' . $imageDetails[0] . 'px; height: ' . $imageDetails[1] . 'px;" src="' . $imageData . '" border="0" />' . PHP_EOL; 700 $html .= '</div>'; 701 702 unlink($chartFileName); 703 } 704 } 705 } 706 } 707 708 // Return 709 return $html; 710 } 711 712 /** 713 * Generate CSS styles 714 * 715 * @param boolean $generateSurroundingHTML Generate surrounding HTML tags? (<style> and </style>) 716 * @return string 717 * @throws PHPExcel_Writer_Exception 718 */ 719 public function generateStyles($generateSurroundingHTML = true) 720 { 721 // PHPExcel object known? 722 if (is_null($this->phpExcel)) { 723 throw new PHPExcel_Writer_Exception('Internal PHPExcel object not set to an instance of an object.'); 724 } 725 726 // Build CSS 727 $css = $this->buildCSS($generateSurroundingHTML); 728 729 // Construct HTML 730 $html = ''; 731 732 // Start styles 733 if ($generateSurroundingHTML) { 734 $html .= ' <style type="text/css">' . PHP_EOL; 735 $html .= ' html { ' . $this->assembleCSS($css['html']) . ' }' . PHP_EOL; 736 } 737 738 // Write all other styles 739 foreach ($css as $styleName => $styleDefinition) { 740 if ($styleName != 'html') { 741 $html .= ' ' . $styleName . ' { ' . $this->assembleCSS($styleDefinition) . ' }' . PHP_EOL; 742 } 743 } 744 745 // End styles 746 if ($generateSurroundingHTML) { 747 $html .= ' </style>' . PHP_EOL; 748 } 749 750 // Return 751 return $html; 752 } 753 754 /** 755 * Build CSS styles 756 * 757 * @param boolean $generateSurroundingHTML Generate surrounding HTML style? (html { }) 758 * @return array 759 * @throws PHPExcel_Writer_Exception 760 */ 761 public function buildCSS($generateSurroundingHTML = true) 762 { 763 // PHPExcel object known? 764 if (is_null($this->phpExcel)) { 765 throw new PHPExcel_Writer_Exception('Internal PHPExcel object not set to an instance of an object.'); 766 } 767 768 // Cached? 769 if (!is_null($this->cssStyles)) { 770 return $this->cssStyles; 771 } 772 773 // Ensure that spans have been calculated 774 if (!$this->spansAreCalculated) { 775 $this->calculateSpans(); 776 } 777 778 // Construct CSS 779 $css = array(); 780 781 // Start styles 782 if ($generateSurroundingHTML) { 783 // html { } 784 $css['html']['font-family'] = 'Calibri, Arial, Helvetica, sans-serif'; 785 $css['html']['font-size'] = '11pt'; 786 $css['html']['background-color'] = 'white'; 787 } 788 789 790 // table { } 791 $css['table']['border-collapse'] = 'collapse'; 792 if (!$this->isPdf) { 793 $css['table']['page-break-after'] = 'always'; 794 } 795 796 // .gridlines td { } 797 $css['.gridlines td']['border'] = '1px dotted black'; 798 $css['.gridlines th']['border'] = '1px dotted black'; 799 800 // .b {} 801 $css['.b']['text-align'] = 'center'; // BOOL 802 803 // .e {} 804 $css['.e']['text-align'] = 'center'; // ERROR 805 806 // .f {} 807 $css['.f']['text-align'] = 'right'; // FORMULA 808 809 // .inlineStr {} 810 $css['.inlineStr']['text-align'] = 'left'; // INLINE 811 812 // .n {} 813 $css['.n']['text-align'] = 'right'; // NUMERIC 814 815 // .s {} 816 $css['.s']['text-align'] = 'left'; // STRING 817 818 // Calculate cell style hashes 819 foreach ($this->phpExcel->getCellXfCollection() as $index => $style) { 820 $css['td.style' . $index] = $this->createCSSStyle($style); 821 $css['th.style' . $index] = $this->createCSSStyle($style); 822 } 823 824 // Fetch sheets 825 $sheets = array(); 826 if (is_null($this->sheetIndex)) { 827 $sheets = $this->phpExcel->getAllSheets(); 828 } else { 829 $sheets[] = $this->phpExcel->getSheet($this->sheetIndex); 830 } 831 832 // Build styles per sheet 833 foreach ($sheets as $sheet) { 834 // Calculate hash code 835 $sheetIndex = $sheet->getParent()->getIndex($sheet); 836 837 // Build styles 838 // Calculate column widths 839 $sheet->calculateColumnWidths(); 840 841 // col elements, initialize 842 $highestColumnIndex = PHPExcel_Cell::columnIndexFromString($sheet->getHighestColumn()) - 1; 843 $column = -1; 844 while ($column++ < $highestColumnIndex) { 845 $this->columnWidths[$sheetIndex][$column] = 42; // approximation 846 $css['table.sheet' . $sheetIndex . ' col.col' . $column]['width'] = '42pt'; 847 } 848 849 // col elements, loop through columnDimensions and set width 850 foreach ($sheet->getColumnDimensions() as $columnDimension) { 851 if (($width = PHPExcel_Shared_Drawing::cellDimensionToPixels($columnDimension->getWidth(), $this->defaultFont)) >= 0) { 852 $width = PHPExcel_Shared_Drawing::pixelsToPoints($width); 853 $column = PHPExcel_Cell::columnIndexFromString($columnDimension->getColumnIndex()) - 1; 854 $this->columnWidths[$sheetIndex][$column] = $width; 855 $css['table.sheet' . $sheetIndex . ' col.col' . $column]['width'] = $width . 'pt'; 856 857 if ($columnDimension->getVisible() === false) { 858 $css['table.sheet' . $sheetIndex . ' col.col' . $column]['visibility'] = 'collapse'; 859 $css['table.sheet' . $sheetIndex . ' col.col' . $column]['*display'] = 'none'; // target IE6+7 860 } 861 } 862 } 863 864 // Default row height 865 $rowDimension = $sheet->getDefaultRowDimension(); 866 867 // table.sheetN tr { } 868 $css['table.sheet' . $sheetIndex . ' tr'] = array(); 869 870 if ($rowDimension->getRowHeight() == -1) { 871 $pt_height = PHPExcel_Shared_Font::getDefaultRowHeightByFont($this->phpExcel->getDefaultStyle()->getFont()); 872 } else { 873 $pt_height = $rowDimension->getRowHeight(); 874 } 875 $css['table.sheet' . $sheetIndex . ' tr']['height'] = $pt_height . 'pt'; 876 if ($rowDimension->getVisible() === false) { 877 $css['table.sheet' . $sheetIndex . ' tr']['display'] = 'none'; 878 $css['table.sheet' . $sheetIndex . ' tr']['visibility'] = 'hidden'; 879 } 880 881 // Calculate row heights 882 foreach ($sheet->getRowDimensions() as $rowDimension) { 883 $row = $rowDimension->getRowIndex() - 1; 884 885 // table.sheetN tr.rowYYYYYY { } 886 $css['table.sheet' . $sheetIndex . ' tr.row' . $row] = array(); 887 888 if ($rowDimension->getRowHeight() == -1) { 889 $pt_height = PHPExcel_Shared_Font::getDefaultRowHeightByFont($this->phpExcel->getDefaultStyle()->getFont()); 890 } else { 891 $pt_height = $rowDimension->getRowHeight(); 892 } 893 $css['table.sheet' . $sheetIndex . ' tr.row' . $row]['height'] = $pt_height . 'pt'; 894 if ($rowDimension->getVisible() === false) { 895 $css['table.sheet' . $sheetIndex . ' tr.row' . $row]['display'] = 'none'; 896 $css['table.sheet' . $sheetIndex . ' tr.row' . $row]['visibility'] = 'hidden'; 897 } 898 } 899 } 900 901 // Cache 902 if (is_null($this->cssStyles)) { 903 $this->cssStyles = $css; 904 } 905 906 // Return 907 return $css; 908 } 909 910 /** 911 * Create CSS style 912 * 913 * @param PHPExcel_Style $pStyle PHPExcel_Style 914 * @return array 915 */ 916 private function createCSSStyle(PHPExcel_Style $pStyle) 917 { 918 // Construct CSS 919 $css = ''; 920 921 // Create CSS 922 $css = array_merge( 923 $this->createCSSStyleAlignment($pStyle->getAlignment()), 924 $this->createCSSStyleBorders($pStyle->getBorders()), 925 $this->createCSSStyleFont($pStyle->getFont()), 926 $this->createCSSStyleFill($pStyle->getFill()) 927 ); 928 929 // Return 930 return $css; 931 } 932 933 /** 934 * Create CSS style (PHPExcel_Style_Alignment) 935 * 936 * @param PHPExcel_Style_Alignment $pStyle PHPExcel_Style_Alignment 937 * @return array 938 */ 939 private function createCSSStyleAlignment(PHPExcel_Style_Alignment $pStyle) 940 { 941 // Construct CSS 942 $css = array(); 943 944 // Create CSS 945 $css['vertical-align'] = $this->mapVAlign($pStyle->getVertical()); 946 if ($textAlign = $this->mapHAlign($pStyle->getHorizontal())) { 947 $css['text-align'] = $textAlign; 948 if (in_array($textAlign, array('left', 'right'))) { 949 $css['padding-'.$textAlign] = (string)((int)$pStyle->getIndent() * 9).'px'; 950 } 951 } 952 953 return $css; 954 } 955 956 /** 957 * Create CSS style (PHPExcel_Style_Font) 958 * 959 * @param PHPExcel_Style_Font $pStyle PHPExcel_Style_Font 960 * @return array 961 */ 962 private function createCSSStyleFont(PHPExcel_Style_Font $pStyle) 963 { 964 // Construct CSS 965 $css = array(); 966 967 // Create CSS 968 if ($pStyle->getBold()) { 969 $css['font-weight'] = 'bold'; 970 } 971 if ($pStyle->getUnderline() != PHPExcel_Style_Font::UNDERLINE_NONE && $pStyle->getStrikethrough()) { 972 $css['text-decoration'] = 'underline line-through'; 973 } elseif ($pStyle->getUnderline() != PHPExcel_Style_Font::UNDERLINE_NONE) { 974 $css['text-decoration'] = 'underline'; 975 } elseif ($pStyle->getStrikethrough()) { 976 $css['text-decoration'] = 'line-through'; 977 } 978 if ($pStyle->getItalic()) { 979 $css['font-style'] = 'italic'; 980 } 981 982 $css['color'] = '#' . $pStyle->getColor()->getRGB(); 983 $css['font-family'] = '\'' . $pStyle->getName() . '\''; 984 $css['font-size'] = $pStyle->getSize() . 'pt'; 985 986 return $css; 987 } 988 989 /** 990 * Create CSS style (PHPExcel_Style_Borders) 991 * 992 * @param PHPExcel_Style_Borders $pStyle PHPExcel_Style_Borders 993 * @return array 994 */ 995 private function createCSSStyleBorders(PHPExcel_Style_Borders $pStyle) 996 { 997 // Construct CSS 998 $css = array(); 999 1000 // Create CSS 1001 $css['border-bottom'] = $this->createCSSStyleBorder($pStyle->getBottom()); 1002 $css['border-top'] = $this->createCSSStyleBorder($pStyle->getTop()); 1003 $css['border-left'] = $this->createCSSStyleBorder($pStyle->getLeft()); 1004 $css['border-right'] = $this->createCSSStyleBorder($pStyle->getRight()); 1005 1006 return $css; 1007 } 1008 1009 /** 1010 * Create CSS style (PHPExcel_Style_Border) 1011 * 1012 * @param PHPExcel_Style_Border $pStyle PHPExcel_Style_Border 1013 * @return string 1014 */ 1015 private function createCSSStyleBorder(PHPExcel_Style_Border $pStyle) 1016 { 1017 // Create CSS 1018 // $css = $this->mapBorderStyle($pStyle->getBorderStyle()) . ' #' . $pStyle->getColor()->getRGB(); 1019 // Create CSS - add !important to non-none border styles for merged cells 1020 $borderStyle = $this->mapBorderStyle($pStyle->getBorderStyle()); 1021 $css = $borderStyle . ' #' . $pStyle->getColor()->getRGB() . (($borderStyle == 'none') ? '' : ' !important'); 1022 1023 return $css; 1024 } 1025 1026 /** 1027 * Create CSS style (PHPExcel_Style_Fill) 1028 * 1029 * @param PHPExcel_Style_Fill $pStyle PHPExcel_Style_Fill 1030 * @return array 1031 */ 1032 private function createCSSStyleFill(PHPExcel_Style_Fill $pStyle) 1033 { 1034 // Construct HTML 1035 $css = array(); 1036 1037 // Create CSS 1038 $value = $pStyle->getFillType() == PHPExcel_Style_Fill::FILL_NONE ? 1039 'white' : '#' . $pStyle->getStartColor()->getRGB(); 1040 $css['background-color'] = $value; 1041 1042 return $css; 1043 } 1044 1045 /** 1046 * Generate HTML footer 1047 */ 1048 public function generateHTMLFooter() 1049 { 1050 // Construct HTML 1051 $html = ''; 1052 $html .= ' </body>' . PHP_EOL; 1053 $html .= '</html>' . PHP_EOL; 1054 1055 return $html; 1056 } 1057 1058 /** 1059 * Generate table header 1060 * 1061 * @param PHPExcel_Worksheet $pSheet The worksheet for the table we are writing 1062 * @return string 1063 * @throws PHPExcel_Writer_Exception 1064 */ 1065 private function generateTableHeader($pSheet) 1066 { 1067 $sheetIndex = $pSheet->getParent()->getIndex($pSheet); 1068 1069 // Construct HTML 1070 $html = ''; 1071 $html .= $this->setMargins($pSheet); 1072 1073 if (!$this->useInlineCss) { 1074 $gridlines = $pSheet->getShowGridlines() ? ' gridlines' : ''; 1075 $html .= ' <table border="0" cellpadding="0" cellspacing="0" id="sheet' . $sheetIndex . '" class="sheet' . $sheetIndex . $gridlines . '">' . PHP_EOL; 1076 } else { 1077 $style = isset($this->cssStyles['table']) ? 1078 $this->assembleCSS($this->cssStyles['table']) : ''; 1079 1080 if ($this->isPdf && $pSheet->getShowGridlines()) { 1081 $html .= ' <table border="1" cellpadding="1" id="sheet' . $sheetIndex . '" cellspacing="1" style="' . $style . '">' . PHP_EOL; 1082 } else { 1083 $html .= ' <table border="0" cellpadding="1" id="sheet' . $sheetIndex . '" cellspacing="0" style="' . $style . '">' . PHP_EOL; 1084 } 1085 } 1086 1087 // Write <col> elements 1088 $highestColumnIndex = PHPExcel_Cell::columnIndexFromString($pSheet->getHighestColumn()) - 1; 1089 $i = -1; 1090 while ($i++ < $highestColumnIndex) { 1091 if (!$this->isPdf) { 1092 if (!$this->useInlineCss) { 1093 $html .= ' <col class="col' . $i . '">' . PHP_EOL; 1094 } else { 1095 $style = isset($this->cssStyles['table.sheet' . $sheetIndex . ' col.col' . $i]) ? 1096 $this->assembleCSS($this->cssStyles['table.sheet' . $sheetIndex . ' col.col' . $i]) : ''; 1097 $html .= ' <col style="' . $style . '">' . PHP_EOL; 1098 } 1099 } 1100 } 1101 1102 return $html; 1103 } 1104 1105 /** 1106 * Generate table footer 1107 * 1108 * @throws PHPExcel_Writer_Exception 1109 */ 1110 private function generateTableFooter() 1111 { 1112 $html = ' </table>' . PHP_EOL; 1113 1114 return $html; 1115 } 1116 1117 /** 1118 * Generate row 1119 * 1120 * @param PHPExcel_Worksheet $pSheet PHPExcel_Worksheet 1121 * @param array $pValues Array containing cells in a row 1122 * @param int $pRow Row number (0-based) 1123 * @return string 1124 * @throws PHPExcel_Writer_Exception 1125 */ 1126 private function generateRow(PHPExcel_Worksheet $pSheet, $pValues = null, $pRow = 0, $cellType = 'td') 1127 { 1128 if (is_array($pValues)) { 1129 // Construct HTML 1130 $html = ''; 1131 1132 // Sheet index 1133 $sheetIndex = $pSheet->getParent()->getIndex($pSheet); 1134 1135 // DomPDF and breaks 1136 if ($this->isPdf && count($pSheet->getBreaks()) > 0) { 1137 $breaks = $pSheet->getBreaks(); 1138 1139 // check if a break is needed before this row 1140 if (isset($breaks['A' . $pRow])) { 1141 // close table: </table> 1142 $html .= $this->generateTableFooter(); 1143 1144 // insert page break 1145 $html .= '<div style="page-break-before:always" />'; 1146 1147 // open table again: <table> + <col> etc. 1148 $html .= $this->generateTableHeader($pSheet); 1149 } 1150 } 1151 1152 // Write row start 1153 if (!$this->useInlineCss) { 1154 $html .= ' <tr class="row' . $pRow . '">' . PHP_EOL; 1155 } else { 1156 $style = isset($this->cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $pRow]) 1157 ? $this->assembleCSS($this->cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $pRow]) : ''; 1158 1159 $html .= ' <tr style="' . $style . '">' . PHP_EOL; 1160 } 1161 1162 // Write cells 1163 $colNum = 0; 1164 foreach ($pValues as $cellAddress) { 1165 $cell = ($cellAddress > '') ? $pSheet->getCell($cellAddress) : ''; 1166 $coordinate = PHPExcel_Cell::stringFromColumnIndex($colNum) . ($pRow + 1); 1167 if (!$this->useInlineCss) { 1168 $cssClass = ''; 1169 $cssClass = 'column' . $colNum; 1170 } else { 1171 $cssClass = array(); 1172 if ($cellType == 'th') { 1173 if (isset($this->cssStyles['table.sheet' . $sheetIndex . ' th.column' . $colNum])) { 1174 $this->cssStyles['table.sheet' . $sheetIndex . ' th.column' . $colNum]; 1175 } 1176 } else { 1177 if (isset($this->cssStyles['table.sheet' . $sheetIndex . ' td.column' . $colNum])) { 1178 $this->cssStyles['table.sheet' . $sheetIndex . ' td.column' . $colNum]; 1179 } 1180 } 1181 } 1182 $colSpan = 1; 1183 $rowSpan = 1; 1184 1185 // initialize 1186 $cellData = ' '; 1187 1188 // PHPExcel_Cell 1189 if ($cell instanceof PHPExcel_Cell) { 1190 $cellData = ''; 1191 if (is_null($cell->getParent())) { 1192 $cell->attach($pSheet); 1193 } 1194 // Value 1195 if ($cell->getValue() instanceof PHPExcel_RichText) { 1196 // Loop through rich text elements 1197 $elements = $cell->getValue()->getRichTextElements(); 1198 foreach ($elements as $element) { 1199 // Rich text start? 1200 if ($element instanceof PHPExcel_RichText_Run) { 1201 $cellData .= '<span style="' . $this->assembleCSS($this->createCSSStyleFont($element->getFont())) . '">'; 1202 1203 if ($element->getFont()->getSuperScript()) { 1204 $cellData .= '<sup>'; 1205 } elseif ($element->getFont()->getSubScript()) { 1206 $cellData .= '<sub>'; 1207 } 1208 } 1209 1210 // Convert UTF8 data to PCDATA 1211 $cellText = $element->getText(); 1212 $cellData .= htmlspecialchars($cellText); 1213 1214 if ($element instanceof PHPExcel_RichText_Run) { 1215 if ($element->getFont()->getSuperScript()) { 1216 $cellData .= '</sup>'; 1217 } elseif ($element->getFont()->getSubScript()) { 1218 $cellData .= '</sub>'; 1219 } 1220 1221 $cellData .= '</span>'; 1222 } 1223 } 1224 } else { 1225 if ($this->preCalculateFormulas) { 1226 $cellData = PHPExcel_Style_NumberFormat::toFormattedString( 1227 $cell->getCalculatedValue(), 1228 $pSheet->getParent()->getCellXfByIndex($cell->getXfIndex())->getNumberFormat()->getFormatCode(), 1229 array($this, 'formatColor') 1230 ); 1231 } else { 1232 $cellData = PHPExcel_Style_NumberFormat::toFormattedString( 1233 $cell->getValue(), 1234 $pSheet->getParent()->getCellXfByIndex($cell->getXfIndex())->getNumberFormat()->getFormatCode(), 1235 array($this, 'formatColor') 1236 ); 1237 } 1238 $cellData = htmlspecialchars($cellData); 1239 if ($pSheet->getParent()->getCellXfByIndex($cell->getXfIndex())->getFont()->getSuperScript()) { 1240 $cellData = '<sup>'.$cellData.'</sup>'; 1241 } elseif ($pSheet->getParent()->getCellXfByIndex($cell->getXfIndex())->getFont()->getSubScript()) { 1242 $cellData = '<sub>'.$cellData.'</sub>'; 1243 } 1244 } 1245 1246 // Converts the cell content so that spaces occuring at beginning of each new line are replaced by 1247 // Example: " Hello\n to the world" is converted to " Hello\n to the world" 1248 $cellData = preg_replace("/(?m)(?:^|\\G) /", ' ', $cellData); 1249 1250 // convert newline "\n" to '<br>' 1251 $cellData = nl2br($cellData); 1252 1253 // Extend CSS class? 1254 if (!$this->useInlineCss) { 1255 $cssClass .= ' style' . $cell->getXfIndex(); 1256 $cssClass .= ' ' . $cell->getDataType(); 1257 } else { 1258 if ($cellType == 'th') { 1259 if (isset($this->cssStyles['th.style' . $cell->getXfIndex()])) { 1260 $cssClass = array_merge($cssClass, $this->cssStyles['th.style' . $cell->getXfIndex()]); 1261 } 1262 } else { 1263 if (isset($this->cssStyles['td.style' . $cell->getXfIndex()])) { 1264 $cssClass = array_merge($cssClass, $this->cssStyles['td.style' . $cell->getXfIndex()]); 1265 } 1266 } 1267 1268 // General horizontal alignment: Actual horizontal alignment depends on dataType 1269 $sharedStyle = $pSheet->getParent()->getCellXfByIndex($cell->getXfIndex()); 1270 if ($sharedStyle->getAlignment()->getHorizontal() == PHPExcel_Style_Alignment::HORIZONTAL_GENERAL 1271 && isset($this->cssStyles['.' . $cell->getDataType()]['text-align'])) { 1272 $cssClass['text-align'] = $this->cssStyles['.' . $cell->getDataType()]['text-align']; 1273 } 1274 } 1275 } 1276 1277 // Hyperlink? 1278 if ($pSheet->hyperlinkExists($coordinate) && !$pSheet->getHyperlink($coordinate)->isInternal()) { 1279 $cellData = '<a href="' . htmlspecialchars($pSheet->getHyperlink($coordinate)->getUrl()) . '" title="' . htmlspecialchars($pSheet->getHyperlink($coordinate)->getTooltip()) . '">' . $cellData . '</a>'; 1280 } 1281 1282 // Should the cell be written or is it swallowed by a rowspan or colspan? 1283 $writeCell = !(isset($this->isSpannedCell[$pSheet->getParent()->getIndex($pSheet)][$pRow + 1][$colNum]) 1284 && $this->isSpannedCell[$pSheet->getParent()->getIndex($pSheet)][$pRow + 1][$colNum]); 1285 1286 // Colspan and Rowspan 1287 $colspan = 1; 1288 $rowspan = 1; 1289 if (isset($this->isBaseCell[$pSheet->getParent()->getIndex($pSheet)][$pRow + 1][$colNum])) { 1290 $spans = $this->isBaseCell[$pSheet->getParent()->getIndex($pSheet)][$pRow + 1][$colNum]; 1291 $rowSpan = $spans['rowspan']; 1292 $colSpan = $spans['colspan']; 1293 1294 // Also apply style from last cell in merge to fix borders - 1295 // relies on !important for non-none border declarations in createCSSStyleBorder 1296 $endCellCoord = PHPExcel_Cell::stringFromColumnIndex($colNum + $colSpan - 1) . ($pRow + $rowSpan); 1297 if (!$this->useInlineCss) { 1298 $cssClass .= ' style' . $pSheet->getCell($endCellCoord)->getXfIndex(); 1299 } 1300 } 1301 1302 // Write 1303 if ($writeCell) { 1304 // Column start 1305 $html .= ' <' . $cellType; 1306 if (!$this->useInlineCss) { 1307 $html .= ' class="' . $cssClass . '"'; 1308 } else { 1309 //** Necessary redundant code for the sake of PHPExcel_Writer_PDF ** 1310 // We must explicitly write the width of the <td> element because TCPDF 1311 // does not recognize e.g. <col style="width:42pt"> 1312 $width = 0; 1313 $i = $colNum - 1; 1314 $e = $colNum + $colSpan - 1; 1315 while ($i++ < $e) { 1316 if (isset($this->columnWidths[$sheetIndex][$i])) { 1317 $width += $this->columnWidths[$sheetIndex][$i]; 1318 } 1319 } 1320 $cssClass['width'] = $width . 'pt'; 1321 1322 // We must also explicitly write the height of the <td> element because TCPDF 1323 // does not recognize e.g. <tr style="height:50pt"> 1324 if (isset($this->cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $pRow]['height'])) { 1325 $height = $this->cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $pRow]['height']; 1326 $cssClass['height'] = $height; 1327 } 1328 //** end of redundant code ** 1329 1330 $html .= ' style="' . $this->assembleCSS($cssClass) . '"'; 1331 } 1332 if ($colSpan > 1) { 1333 $html .= ' colspan="' . $colSpan . '"'; 1334 } 1335 if ($rowSpan > 1) { 1336 $html .= ' rowspan="' . $rowSpan . '"'; 1337 } 1338 $html .= '>'; 1339 1340 // Image? 1341 $html .= $this->writeImageInCell($pSheet, $coordinate); 1342 1343 // Chart? 1344 if ($this->includeCharts) { 1345 $html .= $this->writeChartInCell($pSheet, $coordinate); 1346 } 1347 1348 // Cell data 1349 $html .= $cellData; 1350 1351 // Column end 1352 $html .= '</'.$cellType.'>' . PHP_EOL; 1353 } 1354 1355 // Next column 1356 ++$colNum; 1357 } 1358 1359 // Write row end 1360 $html .= ' </tr>' . PHP_EOL; 1361 1362 // Return 1363 return $html; 1364 } else { 1365 throw new PHPExcel_Writer_Exception("Invalid parameters passed."); 1366 } 1367 } 1368 1369 /** 1370 * Takes array where of CSS properties / values and converts to CSS string 1371 * 1372 * @param array 1373 * @return string 1374 */ 1375 private function assembleCSS($pValue = array()) 1376 { 1377 $pairs = array(); 1378 foreach ($pValue as $property => $value) { 1379 $pairs[] = $property . ':' . $value; 1380 } 1381 $string = implode('; ', $pairs); 1382 1383 return $string; 1384 } 1385 1386 /** 1387 * Get images root 1388 * 1389 * @return string 1390 */ 1391 public function getImagesRoot() 1392 { 1393 return $this->imagesRoot; 1394 } 1395 1396 /** 1397 * Set images root 1398 * 1399 * @param string $pValue 1400 * @return PHPExcel_Writer_HTML 1401 */ 1402 public function setImagesRoot($pValue = '.') 1403 { 1404 $this->imagesRoot = $pValue; 1405 return $this; 1406 } 1407 1408 /** 1409 * Get embed images 1410 * 1411 * @return boolean 1412 */ 1413 public function getEmbedImages() 1414 { 1415 return $this->embedImages; 1416 } 1417 1418 /** 1419 * Set embed images 1420 * 1421 * @param boolean $pValue 1422 * @return PHPExcel_Writer_HTML 1423 */ 1424 public function setEmbedImages($pValue = '.') 1425 { 1426 $this->embedImages = $pValue; 1427 return $this; 1428 } 1429 1430 /** 1431 * Get use inline CSS? 1432 * 1433 * @return boolean 1434 */ 1435 public function getUseInlineCss() 1436 { 1437 return $this->useInlineCss; 1438 } 1439 1440 /** 1441 * Set use inline CSS? 1442 * 1443 * @param boolean $pValue 1444 * @return PHPExcel_Writer_HTML 1445 */ 1446 public function setUseInlineCss($pValue = false) 1447 { 1448 $this->useInlineCss = $pValue; 1449 return $this; 1450 } 1451 1452 /** 1453 * Add color to formatted string as inline style 1454 * 1455 * @param string $pValue Plain formatted value without color 1456 * @param string $pFormat Format code 1457 * @return string 1458 */ 1459 public function formatColor($pValue, $pFormat) 1460 { 1461 // Color information, e.g. [Red] is always at the beginning 1462 $color = null; // initialize 1463 $matches = array(); 1464 1465 $color_regex = '/^\\[[a-zA-Z]+\\]/'; 1466 if (preg_match($color_regex, $pFormat, $matches)) { 1467 $color = str_replace('[', '', $matches[0]); 1468 $color = str_replace(']', '', $color); 1469 $color = strtolower($color); 1470 } 1471 1472 // convert to PCDATA 1473 $value = htmlspecialchars($pValue); 1474 1475 // color span tag 1476 if ($color !== null) { 1477 $value = '<span style="color:' . $color . '">' . $value . '</span>'; 1478 } 1479 1480 return $value; 1481 } 1482 1483 /** 1484 * Calculate information about HTML colspan and rowspan which is not always the same as Excel's 1485 */ 1486 private function calculateSpans() 1487 { 1488 // Identify all cells that should be omitted in HTML due to cell merge. 1489 // In HTML only the upper-left cell should be written and it should have 1490 // appropriate rowspan / colspan attribute 1491 $sheetIndexes = $this->sheetIndex !== null ? 1492 array($this->sheetIndex) : range(0, $this->phpExcel->getSheetCount() - 1); 1493 1494 foreach ($sheetIndexes as $sheetIndex) { 1495 $sheet = $this->phpExcel->getSheet($sheetIndex); 1496 1497 $candidateSpannedRow = array(); 1498 1499 // loop through all Excel merged cells 1500 foreach ($sheet->getMergeCells() as $cells) { 1501 list($cells,) = PHPExcel_Cell::splitRange($cells); 1502 $first = $cells[0]; 1503 $last = $cells[1]; 1504 1505 list($fc, $fr) = PHPExcel_Cell::coordinateFromString($first); 1506 $fc = PHPExcel_Cell::columnIndexFromString($fc) - 1; 1507 1508 list($lc, $lr) = PHPExcel_Cell::coordinateFromString($last); 1509 $lc = PHPExcel_Cell::columnIndexFromString($lc) - 1; 1510 1511 // loop through the individual cells in the individual merge 1512 $r = $fr - 1; 1513 while ($r++ < $lr) { 1514 // also, flag this row as a HTML row that is candidate to be omitted 1515 $candidateSpannedRow[$r] = $r; 1516 1517 $c = $fc - 1; 1518 while ($c++ < $lc) { 1519 if (!($c == $fc && $r == $fr)) { 1520 // not the upper-left cell (should not be written in HTML) 1521 $this->isSpannedCell[$sheetIndex][$r][$c] = array( 1522 'baseCell' => array($fr, $fc), 1523 ); 1524 } else { 1525 // upper-left is the base cell that should hold the colspan/rowspan attribute 1526 $this->isBaseCell[$sheetIndex][$r][$c] = array( 1527 'xlrowspan' => $lr - $fr + 1, // Excel rowspan 1528 'rowspan' => $lr - $fr + 1, // HTML rowspan, value may change 1529 'xlcolspan' => $lc - $fc + 1, // Excel colspan 1530 'colspan' => $lc - $fc + 1, // HTML colspan, value may change 1531 ); 1532 } 1533 } 1534 } 1535 } 1536 1537 // Identify which rows should be omitted in HTML. These are the rows where all the cells 1538 // participate in a merge and the where base cells are somewhere above. 1539 $countColumns = PHPExcel_Cell::columnIndexFromString($sheet->getHighestColumn()); 1540 foreach ($candidateSpannedRow as $rowIndex) { 1541 if (isset($this->isSpannedCell[$sheetIndex][$rowIndex])) { 1542 if (count($this->isSpannedCell[$sheetIndex][$rowIndex]) == $countColumns) { 1543 $this->isSpannedRow[$sheetIndex][$rowIndex] = $rowIndex; 1544 }; 1545 } 1546 } 1547 1548 // For each of the omitted rows we found above, the affected rowspans should be subtracted by 1 1549 if (isset($this->isSpannedRow[$sheetIndex])) { 1550 foreach ($this->isSpannedRow[$sheetIndex] as $rowIndex) { 1551 $adjustedBaseCells = array(); 1552 $c = -1; 1553 $e = $countColumns - 1; 1554 while ($c++ < $e) { 1555 $baseCell = $this->isSpannedCell[$sheetIndex][$rowIndex][$c]['baseCell']; 1556 1557 if (!in_array($baseCell, $adjustedBaseCells)) { 1558 // subtract rowspan by 1 1559 --$this->isBaseCell[$sheetIndex][ $baseCell[0] ][ $baseCell[1] ]['rowspan']; 1560 $adjustedBaseCells[] = $baseCell; 1561 } 1562 } 1563 } 1564 } 1565 1566 // TODO: Same for columns 1567 } 1568 1569 // We have calculated the spans 1570 $this->spansAreCalculated = true; 1571 } 1572 1573 private function setMargins(PHPExcel_Worksheet $pSheet) 1574 { 1575 $htmlPage = '@page { '; 1576 $htmlBody = 'body { '; 1577 1578 $left = PHPExcel_Shared_String::FormatNumber($pSheet->getPageMargins()->getLeft()) . 'in; '; 1579 $htmlPage .= 'margin-left: ' . $left; 1580 $htmlBody .= 'margin-left: ' . $left; 1581 $right = PHPExcel_Shared_String::FormatNumber($pSheet->getPageMargins()->getRight()) . 'in; '; 1582 $htmlPage .= 'margin-right: ' . $right; 1583 $htmlBody .= 'margin-right: ' . $right; 1584 $top = PHPExcel_Shared_String::FormatNumber($pSheet->getPageMargins()->getTop()) . 'in; '; 1585 $htmlPage .= 'margin-top: ' . $top; 1586 $htmlBody .= 'margin-top: ' . $top; 1587 $bottom = PHPExcel_Shared_String::FormatNumber($pSheet->getPageMargins()->getBottom()) . 'in; '; 1588 $htmlPage .= 'margin-bottom: ' . $bottom; 1589 $htmlBody .= 'margin-bottom: ' . $bottom; 1590 1591 $htmlPage .= "}\n"; 1592 $htmlBody .= "}\n"; 1593 1594 return "<style>\n" . $htmlPage . $htmlBody . "</style>\n"; 1595 } 1596 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |