ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Html.php
Go to the documentation of this file.
1<?php
2
4
5use DOMDocument;
6use DOMElement;
7use DOMNode;
8use DOMText;
19use Throwable;
20
22class Html extends BaseReader
23{
27 const TEST_SAMPLE_SIZE = 2048;
28
34 protected $inputEncoding = 'ANSI';
35
41 protected $sheetIndex = 0;
42
48 protected $formats = [
49 'h1' => [
50 'font' => [
51 'bold' => true,
52 'size' => 24,
53 ],
54 ], // Bold, 24pt
55 'h2' => [
56 'font' => [
57 'bold' => true,
58 'size' => 18,
59 ],
60 ], // Bold, 18pt
61 'h3' => [
62 'font' => [
63 'bold' => true,
64 'size' => 13.5,
65 ],
66 ], // Bold, 13.5pt
67 'h4' => [
68 'font' => [
69 'bold' => true,
70 'size' => 12,
71 ],
72 ], // Bold, 12pt
73 'h5' => [
74 'font' => [
75 'bold' => true,
76 'size' => 10,
77 ],
78 ], // Bold, 10pt
79 'h6' => [
80 'font' => [
81 'bold' => true,
82 'size' => 7.5,
83 ],
84 ], // Bold, 7.5pt
85 'a' => [
86 'font' => [
87 'underline' => true,
88 'color' => [
89 'argb' => Color::COLOR_BLUE,
90 ],
91 ],
92 ], // Blue underlined
93 'hr' => [
94 'borders' => [
95 'bottom' => [
96 'borderStyle' => Border::BORDER_THIN,
97 'color' => [
99 ],
100 ],
101 ],
102 ], // Bottom border
103 'strong' => [
104 'font' => [
105 'bold' => true,
106 ],
107 ], // Bold
108 'b' => [
109 'font' => [
110 'bold' => true,
111 ],
112 ], // Bold
113 'i' => [
114 'font' => [
115 'italic' => true,
116 ],
117 ], // Italic
118 'em' => [
119 'font' => [
120 'italic' => true,
121 ],
122 ], // Italic
123 ];
124
125 protected $rowspan = [];
126
130 public function __construct()
131 {
132 parent::__construct();
133 $this->securityScanner = XmlScanner::getInstance($this);
134 }
135
143 public function canRead($pFilename)
144 {
145 // Check if file exists
146 try {
147 $this->openFile($pFilename);
148 } catch (Exception $e) {
149 return false;
150 }
151
152 $beginning = $this->readBeginning();
153 $startWithTag = self::startsWithTag($beginning);
154 $containsTags = self::containsTags($beginning);
155 $endsWithTag = self::endsWithTag($this->readEnding());
156
157 fclose($this->fileHandle);
158
159 return $startWithTag && $containsTags && $endsWithTag;
160 }
161
162 private function readBeginning()
163 {
164 fseek($this->fileHandle, 0);
165
166 return fread($this->fileHandle, self::TEST_SAMPLE_SIZE);
167 }
168
169 private function readEnding()
170 {
171 $meta = stream_get_meta_data($this->fileHandle);
172 $filename = $meta['uri'];
173
174 $size = filesize($filename);
175 if ($size === 0) {
176 return '';
177 }
178
179 $blockSize = self::TEST_SAMPLE_SIZE;
180 if ($size < $blockSize) {
181 $blockSize = $size;
182 }
183
184 fseek($this->fileHandle, $size - $blockSize);
185
186 return fread($this->fileHandle, $blockSize);
187 }
188
189 private static function startsWithTag($data)
190 {
191 return '<' === substr(trim($data), 0, 1);
192 }
193
194 private static function endsWithTag($data)
195 {
196 return '>' === substr(trim($data), -1, 1);
197 }
198
199 private static function containsTags($data)
200 {
201 return strlen($data) !== strlen(strip_tags($data));
202 }
203
211 public function load($pFilename)
212 {
213 // Create new Spreadsheet
214 $spreadsheet = new Spreadsheet();
215
216 // Load into this instance
217 return $this->loadIntoExisting($pFilename, $spreadsheet);
218 }
219
231 public function setInputEncoding($pValue)
232 {
233 $this->inputEncoding = $pValue;
234
235 return $this;
236 }
237
247 public function getInputEncoding()
248 {
250 }
251
252 // Data Array used for testing only, should write to Spreadsheet object on completion of tests
253 protected $dataArray = [];
254
255 protected $tableLevel = 0;
256
257 protected $nestedColumn = ['A'];
258
259 protected function setTableStartColumn($column)
260 {
261 if ($this->tableLevel == 0) {
262 $column = 'A';
263 }
265 $this->nestedColumn[$this->tableLevel] = $column;
266
267 return $this->nestedColumn[$this->tableLevel];
268 }
269
270 protected function getTableStartColumn()
271 {
272 return $this->nestedColumn[$this->tableLevel];
273 }
274
275 protected function releaseTableStartColumn()
276 {
278
279 return array_pop($this->nestedColumn);
280 }
281
282 protected function flushCell(Worksheet $sheet, $column, $row, &$cellContent): void
283 {
284 if (is_string($cellContent)) {
285 // Simple String content
286 if (trim($cellContent) > '') {
287 // Only actually write it if there's content in the string
288 // Write to worksheet to be done here...
289 // ... we return the cell so we can mess about with styles more easily
290 $sheet->setCellValue($column . $row, $cellContent);
291 $this->dataArray[$row][$column] = $cellContent;
292 }
293 } else {
294 // We have a Rich Text run
295 // TODO
296 $this->dataArray[$row][$column] = 'RICH TEXT: ' . $cellContent;
297 }
298 $cellContent = (string) '';
299 }
300
301 private function processDomElementBody(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child): void
302 {
303 $attributeArray = [];
304 foreach ($child->attributes as $attribute) {
305 $attributeArray[$attribute->name] = $attribute->value;
306 }
307
308 if ($child->nodeName === 'body') {
309 $row = 1;
310 $column = 'A';
311 $cellContent = '';
312 $this->tableLevel = 0;
313 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
314 } else {
315 $this->processDomElementTitle($sheet, $row, $column, $cellContent, $child, $attributeArray);
316 }
317 }
318
319 private function processDomElementTitle(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
320 {
321 if ($child->nodeName === 'title') {
322 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
323 $sheet->setTitle($cellContent, true, true);
324 $cellContent = '';
325 } else {
326 $this->processDomElementSpanEtc($sheet, $row, $column, $cellContent, $child, $attributeArray);
327 }
328 }
329
330 private static $spanEtc = ['span', 'div', 'font', 'i', 'em', 'strong', 'b'];
331
332 private function processDomElementSpanEtc(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
333 {
334 if (in_array($child->nodeName, self::$spanEtc)) {
335 if (isset($attributeArray['class']) && $attributeArray['class'] === 'comment') {
336 $sheet->getComment($column . $row)
337 ->getText()
338 ->createTextRun($child->textContent);
339 }
340 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
341
342 if (isset($this->formats[$child->nodeName])) {
343 $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
344 }
345 } else {
346 $this->processDomElementHr($sheet, $row, $column, $cellContent, $child, $attributeArray);
347 }
348 }
349
350 private function processDomElementHr(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
351 {
352 if ($child->nodeName === 'hr') {
353 $this->flushCell($sheet, $column, $row, $cellContent);
354 ++$row;
355 if (isset($this->formats[$child->nodeName])) {
356 $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
357 }
358 ++$row;
359 }
360 // fall through to br
361 $this->processDomElementBr($sheet, $row, $column, $cellContent, $child, $attributeArray);
362 }
363
364 private function processDomElementBr(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
365 {
366 if ($child->nodeName === 'br' || $child->nodeName === 'hr') {
367 if ($this->tableLevel > 0) {
368 // If we're inside a table, replace with a \n and set the cell to wrap
369 $cellContent .= "\n";
370 $sheet->getStyle($column . $row)->getAlignment()->setWrapText(true);
371 } else {
372 // Otherwise flush our existing content and move the row cursor on
373 $this->flushCell($sheet, $column, $row, $cellContent);
374 ++$row;
375 }
376 } else {
377 $this->processDomElementA($sheet, $row, $column, $cellContent, $child, $attributeArray);
378 }
379 }
380
381 private function processDomElementA(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
382 {
383 if ($child->nodeName === 'a') {
384 foreach ($attributeArray as $attributeName => $attributeValue) {
385 switch ($attributeName) {
386 case 'href':
387 $sheet->getCell($column . $row)->getHyperlink()->setUrl($attributeValue);
388 if (isset($this->formats[$child->nodeName])) {
389 $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
390 }
391
392 break;
393 case 'class':
394 if ($attributeValue === 'comment-indicator') {
395 break; // Ignore - it's just a red square.
396 }
397 }
398 }
399 // no idea why this should be needed
400 //$cellContent .= ' ';
401 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
402 } else {
403 $this->processDomElementH1Etc($sheet, $row, $column, $cellContent, $child, $attributeArray);
404 }
405 }
406
407 private static $h1Etc = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'ul', 'p'];
408
409 private function processDomElementH1Etc(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
410 {
411 if (in_array($child->nodeName, self::$h1Etc)) {
412 if ($this->tableLevel > 0) {
413 // If we're inside a table, replace with a \n
414 $cellContent .= $cellContent ? "\n" : '';
415 $sheet->getStyle($column . $row)->getAlignment()->setWrapText(true);
416 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
417 } else {
418 if ($cellContent > '') {
419 $this->flushCell($sheet, $column, $row, $cellContent);
420 ++$row;
421 }
422 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
423 $this->flushCell($sheet, $column, $row, $cellContent);
424
425 if (isset($this->formats[$child->nodeName])) {
426 $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
427 }
428
429 ++$row;
430 $column = 'A';
431 }
432 } else {
433 $this->processDomElementLi($sheet, $row, $column, $cellContent, $child, $attributeArray);
434 }
435 }
436
437 private function processDomElementLi(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
438 {
439 if ($child->nodeName === 'li') {
440 if ($this->tableLevel > 0) {
441 // If we're inside a table, replace with a \n
442 $cellContent .= $cellContent ? "\n" : '';
443 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
444 } else {
445 if ($cellContent > '') {
446 $this->flushCell($sheet, $column, $row, $cellContent);
447 }
448 ++$row;
449 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
450 $this->flushCell($sheet, $column, $row, $cellContent);
451 $column = 'A';
452 }
453 } else {
454 $this->processDomElementImg($sheet, $row, $column, $cellContent, $child, $attributeArray);
455 }
456 }
457
458 private function processDomElementImg(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
459 {
460 if ($child->nodeName === 'img') {
461 $this->insertImage($sheet, $column, $row, $attributeArray);
462 } else {
463 $this->processDomElementTable($sheet, $row, $column, $cellContent, $child, $attributeArray);
464 }
465 }
466
467 private function processDomElementTable(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
468 {
469 if ($child->nodeName === 'table') {
470 $this->flushCell($sheet, $column, $row, $cellContent);
471 $column = $this->setTableStartColumn($column);
472 if ($this->tableLevel > 1 && $row > 1) {
473 --$row;
474 }
475 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
476 $column = $this->releaseTableStartColumn();
477 if ($this->tableLevel > 1) {
478 ++$column;
479 } else {
480 ++$row;
481 }
482 } else {
483 $this->processDomElementTr($sheet, $row, $column, $cellContent, $child, $attributeArray);
484 }
485 }
486
487 private function processDomElementTr(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
488 {
489 if ($child->nodeName === 'tr') {
490 $column = $this->getTableStartColumn();
491 $cellContent = '';
492 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
493
494 if (isset($attributeArray['height'])) {
495 $sheet->getRowDimension($row)->setRowHeight($attributeArray['height']);
496 }
497
498 ++$row;
499 } else {
500 $this->processDomElementThTdOther($sheet, $row, $column, $cellContent, $child, $attributeArray);
501 }
502 }
503
504 private function processDomElementThTdOther(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
505 {
506 if ($child->nodeName !== 'td' && $child->nodeName !== 'th') {
507 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
508 } else {
509 $this->processDomElementThTd($sheet, $row, $column, $cellContent, $child, $attributeArray);
510 }
511 }
512
513 private function processDomElementBgcolor(Worksheet $sheet, int $row, string $column, array $attributeArray): void
514 {
515 if (isset($attributeArray['bgcolor'])) {
516 $sheet->getStyle("$column$row")->applyFromArray(
517 [
518 'fill' => [
519 'fillType' => Fill::FILL_SOLID,
520 'color' => ['rgb' => $this->getStyleColor($attributeArray['bgcolor'])],
521 ],
522 ]
523 );
524 }
525 }
526
527 private function processDomElementWidth(Worksheet $sheet, string $column, array $attributeArray): void
528 {
529 if (isset($attributeArray['width'])) {
530 $sheet->getColumnDimension($column)->setWidth($attributeArray['width']);
531 }
532 }
533
534 private function processDomElementHeight(Worksheet $sheet, int $row, array $attributeArray): void
535 {
536 if (isset($attributeArray['height'])) {
537 $sheet->getRowDimension($row)->setRowHeight($attributeArray['height']);
538 }
539 }
540
541 private function processDomElementAlign(Worksheet $sheet, int $row, string $column, array $attributeArray): void
542 {
543 if (isset($attributeArray['align'])) {
544 $sheet->getStyle($column . $row)->getAlignment()->setHorizontal($attributeArray['align']);
545 }
546 }
547
548 private function processDomElementVAlign(Worksheet $sheet, int $row, string $column, array $attributeArray): void
549 {
550 if (isset($attributeArray['valign'])) {
551 $sheet->getStyle($column . $row)->getAlignment()->setVertical($attributeArray['valign']);
552 }
553 }
554
555 private function processDomElementDataFormat(Worksheet $sheet, int $row, string $column, array $attributeArray): void
556 {
557 if (isset($attributeArray['data-format'])) {
558 $sheet->getStyle($column . $row)->getNumberFormat()->setFormatCode($attributeArray['data-format']);
559 }
560 }
561
562 private function processDomElementThTd(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void
563 {
564 while (isset($this->rowspan[$column . $row])) {
565 ++$column;
566 }
567 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
568
569 // apply inline style
570 $this->applyInlineStyle($sheet, $row, $column, $attributeArray);
571
572 $this->flushCell($sheet, $column, $row, $cellContent);
573
574 $this->processDomElementBgcolor($sheet, $row, $column, $attributeArray);
575 $this->processDomElementWidth($sheet, $column, $attributeArray);
576 $this->processDomElementHeight($sheet, $row, $attributeArray);
577 $this->processDomElementAlign($sheet, $row, $column, $attributeArray);
578 $this->processDomElementVAlign($sheet, $row, $column, $attributeArray);
579 $this->processDomElementDataFormat($sheet, $row, $column, $attributeArray);
580
581 if (isset($attributeArray['rowspan'], $attributeArray['colspan'])) {
582 //create merging rowspan and colspan
583 $columnTo = $column;
584 for ($i = 0; $i < (int) $attributeArray['colspan'] - 1; ++$i) {
585 ++$columnTo;
586 }
587 $range = $column . $row . ':' . $columnTo . ($row + (int) $attributeArray['rowspan'] - 1);
588 foreach (Coordinate::extractAllCellReferencesInRange($range) as $value) {
589 $this->rowspan[$value] = true;
590 }
591 $sheet->mergeCells($range);
592 $column = $columnTo;
593 } elseif (isset($attributeArray['rowspan'])) {
594 //create merging rowspan
595 $range = $column . $row . ':' . $column . ($row + (int) $attributeArray['rowspan'] - 1);
596 foreach (Coordinate::extractAllCellReferencesInRange($range) as $value) {
597 $this->rowspan[$value] = true;
598 }
599 $sheet->mergeCells($range);
600 } elseif (isset($attributeArray['colspan'])) {
601 //create merging colspan
602 $columnTo = $column;
603 for ($i = 0; $i < (int) $attributeArray['colspan'] - 1; ++$i) {
604 ++$columnTo;
605 }
606 $sheet->mergeCells($column . $row . ':' . $columnTo . $row);
607 $column = $columnTo;
608 }
609
610 ++$column;
611 }
612
613 protected function processDomElement(DOMNode $element, Worksheet $sheet, int &$row, string &$column, string &$cellContent): void
614 {
615 foreach ($element->childNodes as $child) {
616 if ($child instanceof DOMText) {
617 $domText = preg_replace('/\s+/u', ' ', trim($child->nodeValue));
618 if (is_string($cellContent)) {
619 // simply append the text if the cell content is a plain text string
620 $cellContent .= $domText;
621 }
622 // but if we have a rich text run instead, we need to append it correctly
623 // TODO
624 } elseif ($child instanceof DOMElement) {
625 $this->processDomElementBody($sheet, $row, $column, $cellContent, $child);
626 }
627 }
628 }
629
637 public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
638 {
639 // Validate
640 if (!$this->canRead($pFilename)) {
641 throw new Exception($pFilename . ' is an Invalid HTML file.');
642 }
643
644 // Create a new DOM object
645 $dom = new DOMDocument();
646 // Reload the HTML file into the DOM object
647 try {
648 $loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanner->scanFile($pFilename), 'HTML-ENTITIES', 'UTF-8'));
649 } catch (Throwable $e) {
650 $loaded = false;
651 }
652 if ($loaded === false) {
653 throw new Exception('Failed to load ' . $pFilename . ' as a DOM Document', 0, $e ?? null);
654 }
655
656 return $this->loadDocument($dom, $spreadsheet);
657 }
658
664 public function loadFromString($content, ?Spreadsheet $spreadsheet = null): Spreadsheet
665 {
666 // Create a new DOM object
667 $dom = new DOMDocument();
668 // Reload the HTML file into the DOM object
669 try {
670 $loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanner->scan($content), 'HTML-ENTITIES', 'UTF-8'));
671 } catch (Throwable $e) {
672 $loaded = false;
673 }
674 if ($loaded === false) {
675 throw new Exception('Failed to load content as a DOM Document', 0, $e ?? null);
676 }
677
678 return $this->loadDocument($dom, $spreadsheet ?? new Spreadsheet());
679 }
680
684 private function loadDocument(DOMDocument $document, Spreadsheet $spreadsheet): Spreadsheet
685 {
686 while ($spreadsheet->getSheetCount() <= $this->sheetIndex) {
687 $spreadsheet->createSheet();
688 }
689 $spreadsheet->setActiveSheetIndex($this->sheetIndex);
690
691 // Discard white space
692 $document->preserveWhiteSpace = false;
693
694 $row = 0;
695 $column = 'A';
696 $content = '';
697 $this->rowspan = [];
698 $this->processDomElement($document, $spreadsheet->getActiveSheet(), $row, $column, $content);
699
700 // Return
701 return $spreadsheet;
702 }
703
709 public function getSheetIndex()
710 {
711 return $this->sheetIndex;
712 }
713
721 public function setSheetIndex($pValue)
722 {
723 $this->sheetIndex = $pValue;
724
725 return $this;
726 }
727
743 private function applyInlineStyle(&$sheet, $row, $column, $attributeArray): void
744 {
745 if (!isset($attributeArray['style'])) {
746 return;
747 }
748
749 if (isset($attributeArray['rowspan'], $attributeArray['colspan'])) {
750 $columnTo = $column;
751 for ($i = 0; $i < (int) $attributeArray['colspan'] - 1; ++$i) {
752 ++$columnTo;
753 }
754 $range = $column . $row . ':' . $columnTo . ($row + (int) $attributeArray['rowspan'] - 1);
755 $cellStyle = $sheet->getStyle($range);
756 } elseif (isset($attributeArray['rowspan'])) {
757 $range = $column . $row . ':' . $column . ($row + (int) $attributeArray['rowspan'] - 1);
758 $cellStyle = $sheet->getStyle($range);
759 } elseif (isset($attributeArray['colspan'])) {
760 $columnTo = $column;
761 for ($i = 0; $i < (int) $attributeArray['colspan'] - 1; ++$i) {
762 ++$columnTo;
763 }
764 $range = $column . $row . ':' . $columnTo . $row;
765 $cellStyle = $sheet->getStyle($range);
766 } else {
767 $cellStyle = $sheet->getStyle($column . $row);
768 }
769
770 // add color styles (background & text) from dom element,currently support : td & th, using ONLY inline css style with RGB color
771 $styles = explode(';', $attributeArray['style']);
772 foreach ($styles as $st) {
773 $value = explode(':', $st);
774 $styleName = isset($value[0]) ? trim($value[0]) : null;
775 $styleValue = isset($value[1]) ? trim($value[1]) : null;
776
777 if (!$styleName) {
778 continue;
779 }
780
781 switch ($styleName) {
782 case 'background':
783 case 'background-color':
784 $styleColor = $this->getStyleColor($styleValue);
785
786 if (!$styleColor) {
787 continue 2;
788 }
789
790 $cellStyle->applyFromArray(['fill' => ['fillType' => Fill::FILL_SOLID, 'color' => ['rgb' => $styleColor]]]);
791
792 break;
793 case 'color':
794 $styleColor = $this->getStyleColor($styleValue);
795
796 if (!$styleColor) {
797 continue 2;
798 }
799
800 $cellStyle->applyFromArray(['font' => ['color' => ['rgb' => $styleColor]]]);
801
802 break;
803
804 case 'border':
805 $this->setBorderStyle($cellStyle, $styleValue, 'allBorders');
806
807 break;
808
809 case 'border-top':
810 $this->setBorderStyle($cellStyle, $styleValue, 'top');
811
812 break;
813
814 case 'border-bottom':
815 $this->setBorderStyle($cellStyle, $styleValue, 'bottom');
816
817 break;
818
819 case 'border-left':
820 $this->setBorderStyle($cellStyle, $styleValue, 'left');
821
822 break;
823
824 case 'border-right':
825 $this->setBorderStyle($cellStyle, $styleValue, 'right');
826
827 break;
828
829 case 'font-size':
830 $cellStyle->getFont()->setSize(
831 (float) $styleValue
832 );
833
834 break;
835
836 case 'font-weight':
837 if ($styleValue === 'bold' || $styleValue >= 500) {
838 $cellStyle->getFont()->setBold(true);
839 }
840
841 break;
842
843 case 'font-style':
844 if ($styleValue === 'italic') {
845 $cellStyle->getFont()->setItalic(true);
846 }
847
848 break;
849
850 case 'font-family':
851 $cellStyle->getFont()->setName(str_replace('\'', '', $styleValue));
852
853 break;
854
855 case 'text-decoration':
856 switch ($styleValue) {
857 case 'underline':
858 $cellStyle->getFont()->setUnderline(Font::UNDERLINE_SINGLE);
859
860 break;
861 case 'line-through':
862 $cellStyle->getFont()->setStrikethrough(true);
863
864 break;
865 }
866
867 break;
868
869 case 'text-align':
870 $cellStyle->getAlignment()->setHorizontal($styleValue);
871
872 break;
873
874 case 'vertical-align':
875 $cellStyle->getAlignment()->setVertical($styleValue);
876
877 break;
878
879 case 'width':
880 $sheet->getColumnDimension($column)->setWidth(
881 (float) str_replace(['px', 'pt'], '', $styleValue)
882 );
883
884 break;
885
886 case 'height':
887 $sheet->getRowDimension($row)->setRowHeight(
888 (float) str_replace(['px', 'pt'], '', $styleValue)
889 );
890
891 break;
892
893 case 'word-wrap':
894 $cellStyle->getAlignment()->setWrapText(
895 $styleValue === 'break-word'
896 );
897
898 break;
899
900 case 'text-indent':
901 $cellStyle->getAlignment()->setIndent(
902 (int) str_replace(['px'], '', $styleValue)
903 );
904
905 break;
906 }
907 }
908 }
909
915 public function getStyleColor($value)
916 {
917 if (strpos($value, '#') === 0) {
918 return substr($value, 1);
919 }
920
921 return \PhpOffice\PhpSpreadsheet\Helper\Html::colourNameLookup((string) $value);
922 }
923
928 private function insertImage(Worksheet $sheet, $column, $row, array $attributes): void
929 {
930 if (!isset($attributes['src'])) {
931 return;
932 }
933
934 $src = urldecode($attributes['src']);
935 $width = isset($attributes['width']) ? (float) $attributes['width'] : null;
936 $height = isset($attributes['height']) ? (float) $attributes['height'] : null;
937 $name = $attributes['alt'] ?? null;
938
939 $drawing = new Drawing();
940 $drawing->setPath($src);
941 $drawing->setWorksheet($sheet);
942 $drawing->setCoordinates($column . $row);
943 $drawing->setOffsetX(0);
944 $drawing->setOffsetY(10);
945 $drawing->setResizeProportional(true);
946
947 if ($name) {
948 $drawing->setName($name);
949 }
950
951 if ($width) {
952 $drawing->setWidth((int) $width);
953 }
954
955 if ($height) {
956 $drawing->setHeight((int) $height);
957 }
958
959 $sheet->getColumnDimension($column)->setWidth(
960 $drawing->getWidth() / 6
961 );
962
963 $sheet->getRowDimension($row)->setRowHeight(
964 $drawing->getHeight() * 0.9
965 );
966 }
967
968 private static $borderMappings = [
969 'dash-dot' => Border::BORDER_DASHDOT,
970 'dash-dot-dot' => Border::BORDER_DASHDOTDOT,
971 'dashed' => Border::BORDER_DASHED,
972 'dotted' => Border::BORDER_DOTTED,
973 'double' => Border::BORDER_DOUBLE,
974 'hair' => Border::BORDER_HAIR,
975 'medium' => Border::BORDER_MEDIUM,
976 'medium-dashed' => Border::BORDER_MEDIUMDASHED,
977 'medium-dash-dot' => Border::BORDER_MEDIUMDASHDOT,
978 'medium-dash-dot-dot' => Border::BORDER_MEDIUMDASHDOTDOT,
979 'none' => Border::BORDER_NONE,
980 'slant-dash-dot' => Border::BORDER_SLANTDASHDOT,
981 'solid' => Border::BORDER_THIN,
982 'thick' => Border::BORDER_THICK,
983 ];
984
985 public static function getBorderMappings(): array
986 {
988 }
989
997 public function getBorderStyle($style)
998 {
999 return (array_key_exists($style, self::$borderMappings)) ? self::$borderMappings[$style] : null;
1000 }
1001
1006 private function setBorderStyle(Style $cellStyle, $styleValue, $type): void
1007 {
1008 if (trim($styleValue) === Border::BORDER_NONE) {
1009 $borderStyle = Border::BORDER_NONE;
1010 $color = null;
1011 } else {
1012 $borderArray = explode(' ', $styleValue);
1013 $borderCount = count($borderArray);
1014 if ($borderCount >= 3) {
1015 $borderStyle = $borderArray[1];
1016 $color = $borderArray[2];
1017 } else {
1018 $borderStyle = $borderArray[0];
1019 $color = $borderArray[1] ?? null;
1020 }
1021 }
1022
1023 $cellStyle->applyFromArray([
1024 'borders' => [
1025 $type => [
1026 'borderStyle' => $this->getBorderStyle($borderStyle),
1027 'color' => ['rgb' => $this->getStyleColor($color)],
1028 ],
1029 ],
1030 ]);
1031 }
1032}
$size
Definition: RandomTest.php:84
$filename
Definition: buildRTE.php:89
An exception for terminatinating execution or to throw for unit testing.
Helper class to manipulate cell coordinates.
Definition: Coordinate.php:15
static extractAllCellReferencesInRange($cellRange)
Extract all cell references in range, which may be comprised of multiple cell ranges.
Definition: Coordinate.php:338
openFile($pFilename)
Open file for reading.
Definition: BaseReader.php:145
PhpSpreadsheet root directory.
Definition: Html.php:23
const TEST_SAMPLE_SIZE
Sample size to read to determine if it's HTML or not.
Definition: Html.php:27
processDomElement(DOMNode $element, Worksheet $sheet, int &$row, string &$column, string &$cellContent)
Definition: Html.php:613
processDomElementTitle(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray)
Definition: Html.php:319
processDomElementAlign(Worksheet $sheet, int $row, string $column, array $attributeArray)
Definition: Html.php:541
processDomElementBody(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child)
Definition: Html.php:301
loadDocument(DOMDocument $document, Spreadsheet $spreadsheet)
Loads PhpSpreadsheet from DOMDocument into PhpSpreadsheet instance.
Definition: Html.php:684
processDomElementSpanEtc(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray)
Definition: Html.php:332
load($pFilename)
Loads Spreadsheet from file.
Definition: Html.php:211
processDomElementHeight(Worksheet $sheet, int $row, array $attributeArray)
Definition: Html.php:534
flushCell(Worksheet $sheet, $column, $row, &$cellContent)
Definition: Html.php:282
getSheetIndex()
Get sheet index.
Definition: Html.php:709
getInputEncoding()
Get input encoding.
Definition: Html.php:247
__construct()
Create a new HTML Reader instance.
Definition: Html.php:130
getStyleColor($value)
Check if has #, so we can get clean hex.
Definition: Html.php:915
processDomElementH1Etc(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray)
Definition: Html.php:409
processDomElementTr(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray)
Definition: Html.php:487
processDomElementTable(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray)
Definition: Html.php:467
setSheetIndex($pValue)
Set sheet index.
Definition: Html.php:721
canRead($pFilename)
Validate that the current file is an HTML file.
Definition: Html.php:143
applyInlineStyle(&$sheet, $row, $column, $attributeArray)
Apply inline css inline style.
Definition: Html.php:743
insertImage(Worksheet $sheet, $column, $row, array $attributes)
Definition: Html.php:928
processDomElementDataFormat(Worksheet $sheet, int $row, string $column, array $attributeArray)
Definition: Html.php:555
getBorderStyle($style)
Map html border style to PhpSpreadsheet border style.
Definition: Html.php:997
processDomElementLi(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray)
Definition: Html.php:437
processDomElementImg(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray)
Definition: Html.php:458
processDomElementBr(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray)
Definition: Html.php:364
processDomElementWidth(Worksheet $sheet, string $column, array $attributeArray)
Definition: Html.php:527
processDomElementThTd(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray)
Definition: Html.php:562
processDomElementVAlign(Worksheet $sheet, int $row, string $column, array $attributeArray)
Definition: Html.php:548
setBorderStyle(Style $cellStyle, $styleValue, $type)
Definition: Html.php:1006
processDomElementA(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray)
Definition: Html.php:381
loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
Loads PhpSpreadsheet from file into PhpSpreadsheet instance.
Definition: Html.php:637
setInputEncoding($pValue)
Set input encoding.
Definition: Html.php:231
loadFromString($content, ?Spreadsheet $spreadsheet=null)
Spreadsheet from content.
Definition: Html.php:664
processDomElementBgcolor(Worksheet $sheet, int $row, string $column, array $attributeArray)
Definition: Html.php:513
processDomElementHr(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray)
Definition: Html.php:350
processDomElementThTdOther(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray)
Definition: Html.php:504
static getInstance(Reader\IReader $reader)
Definition: XmlScanner.php:39
createSheet($sheetIndex=null)
Create sheet and add it to this workbook.
setActiveSheetIndex($pIndex)
Set active sheet index.
$i
Definition: disco.tpl.php:19
$style
Definition: example_012.php:70
if(array_key_exists('yes', $_REQUEST)) $attributes
Definition: getconsent.php:85
$row
$type
$data
Definition: bench.php:6