PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.5.0
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.5.0
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
visualizer / vendor / phpoffice / phpspreadsheet / src / PhpSpreadsheet / Reader / Html.php

Html.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.5.0, at vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Html.php

934 lines 30.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace PhpOffice\PhpSpreadsheet\Reader;
4
5 use DOMDocument;
6 use DOMElement;
7 use DOMNode;
8 use DOMText;
9 use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
10 use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
11 use PhpOffice\PhpSpreadsheet\Spreadsheet;
12 use PhpOffice\PhpSpreadsheet\Style\Border;
13 use PhpOffice\PhpSpreadsheet\Style\Color;
14 use PhpOffice\PhpSpreadsheet\Style\Fill;
15 use PhpOffice\PhpSpreadsheet\Style\Font;
16 use PhpOffice\PhpSpreadsheet\Style\Style;
17 use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
18 use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
19
20 /** PhpSpreadsheet root directory */
21 class Html extends BaseReader
22 {
23 /**
24 * Sample size to read to determine if it's HTML or not.
25 */
26 const TEST_SAMPLE_SIZE = 2048;
27
28 /**
29 * Input encoding.
30 *
31 * @var string
32 */
33 protected $inputEncoding = 'ANSI';
34
35 /**
36 * Sheet index to read.
37 *
38 * @var int
39 */
40 protected $sheetIndex = 0;
41
42 /**
43 * Formats.
44 *
45 * @var array
46 */
47 protected $formats = [
48 'h1' => [
49 'font' => [
50 'bold' => true,
51 'size' => 24,
52 ],
53 ], // Bold, 24pt
54 'h2' => [
55 'font' => [
56 'bold' => true,
57 'size' => 18,
58 ],
59 ], // Bold, 18pt
60 'h3' => [
61 'font' => [
62 'bold' => true,
63 'size' => 13.5,
64 ],
65 ], // Bold, 13.5pt
66 'h4' => [
67 'font' => [
68 'bold' => true,
69 'size' => 12,
70 ],
71 ], // Bold, 12pt
72 'h5' => [
73 'font' => [
74 'bold' => true,
75 'size' => 10,
76 ],
77 ], // Bold, 10pt
78 'h6' => [
79 'font' => [
80 'bold' => true,
81 'size' => 7.5,
82 ],
83 ], // Bold, 7.5pt
84 'a' => [
85 'font' => [
86 'underline' => true,
87 'color' => [
88 'argb' => Color::COLOR_BLUE,
89 ],
90 ],
91 ], // Blue underlined
92 'hr' => [
93 'borders' => [
94 'bottom' => [
95 'borderStyle' => Border::BORDER_THIN,
96 'color' => [
97 Color::COLOR_BLACK,
98 ],
99 ],
100 ],
101 ], // Bottom border
102 'strong' => [
103 'font' => [
104 'bold' => true,
105 ],
106 ], // Bold
107 'b' => [
108 'font' => [
109 'bold' => true,
110 ],
111 ], // Bold
112 'i' => [
113 'font' => [
114 'italic' => true,
115 ],
116 ], // Italic
117 'em' => [
118 'font' => [
119 'italic' => true,
120 ],
121 ], // Italic
122 ];
123
124 protected $rowspan = [];
125
126 /**
127 * Create a new HTML Reader instance.
128 */
129 public function __construct()
130 {
131 parent::__construct();
132 $this->securityScanner = XmlScanner::getInstance($this);
133 }
134
135 /**
136 * Validate that the current file is an HTML file.
137 *
138 * @param string $pFilename
139 *
140 * @return bool
141 */
142 public function canRead($pFilename)
143 {
144 // Check if file exists
145 try {
146 $this->openFile($pFilename);
147 } catch (Exception $e) {
148 return false;
149 }
150
151 $beginning = $this->readBeginning();
152 $startWithTag = self::startsWithTag($beginning);
153 $containsTags = self::containsTags($beginning);
154 $endsWithTag = self::endsWithTag($this->readEnding());
155
156 fclose($this->fileHandle);
157
158 return $startWithTag && $containsTags && $endsWithTag;
159 }
160
161 private function readBeginning()
162 {
163 fseek($this->fileHandle, 0);
164
165 return fread($this->fileHandle, self::TEST_SAMPLE_SIZE);
166 }
167
168 private function readEnding()
169 {
170 $meta = stream_get_meta_data($this->fileHandle);
171 $filename = $meta['uri'];
172
173 $size = filesize($filename);
174 if ($size === 0) {
175 return '';
176 }
177
178 $blockSize = self::TEST_SAMPLE_SIZE;
179 if ($size < $blockSize) {
180 $blockSize = $size;
181 }
182
183 fseek($this->fileHandle, $size - $blockSize);
184
185 return fread($this->fileHandle, $blockSize);
186 }
187
188 private static function startsWithTag($data)
189 {
190 return '<' === substr(trim($data), 0, 1);
191 }
192
193 private static function endsWithTag($data)
194 {
195 return '>' === substr(trim($data), -1, 1);
196 }
197
198 private static function containsTags($data)
199 {
200 return strlen($data) !== strlen(strip_tags($data));
201 }
202
203 /**
204 * Loads Spreadsheet from file.
205 *
206 * @param string $pFilename
207 *
208 * @throws Exception
209 *
210 * @return Spreadsheet
211 */
212 public function load($pFilename)
213 {
214 // Create new Spreadsheet
215 $spreadsheet = new Spreadsheet();
216
217 // Load into this instance
218 return $this->loadIntoExisting($pFilename, $spreadsheet);
219 }
220
221 /**
222 * Set input encoding.
223 *
224 * @param string $pValue Input encoding, eg: 'ANSI'
225 *
226 * @return Html
227 */
228 public function setInputEncoding($pValue)
229 {
230 $this->inputEncoding = $pValue;
231
232 return $this;
233 }
234
235 /**
236 * Get input encoding.
237 *
238 * @return string
239 */
240 public function getInputEncoding()
241 {
242 return $this->inputEncoding;
243 }
244
245 // Data Array used for testing only, should write to Spreadsheet object on completion of tests
246 protected $dataArray = [];
247
248 protected $tableLevel = 0;
249
250 protected $nestedColumn = ['A'];
251
252 protected function setTableStartColumn($column)
253 {
254 if ($this->tableLevel == 0) {
255 $column = 'A';
256 }
257 ++$this->tableLevel;
258 $this->nestedColumn[$this->tableLevel] = $column;
259
260 return $this->nestedColumn[$this->tableLevel];
261 }
262
263 protected function getTableStartColumn()
264 {
265 return $this->nestedColumn[$this->tableLevel];
266 }
267
268 protected function releaseTableStartColumn()
269 {
270 --$this->tableLevel;
271
272 return array_pop($this->nestedColumn);
273 }
274
275 protected function flushCell(Worksheet $sheet, $column, $row, &$cellContent)
276 {
277 if (is_string($cellContent)) {
278 // Simple String content
279 if (trim($cellContent) > '') {
280 // Only actually write it if there's content in the string
281 // Write to worksheet to be done here...
282 // ... we return the cell so we can mess about with styles more easily
283 $sheet->setCellValue($column . $row, $cellContent);
284 $this->dataArray[$row][$column] = $cellContent;
285 }
286 } else {
287 // We have a Rich Text run
288 // TODO
289 $this->dataArray[$row][$column] = 'RICH TEXT: ' . $cellContent;
290 }
291 $cellContent = (string) '';
292 }
293
294 /**
295 * @param DOMNode $element
296 * @param Worksheet $sheet
297 * @param int $row
298 * @param string $column
299 * @param string $cellContent
300 */
301 protected function processDomElement(DOMNode $element, Worksheet $sheet, &$row, &$column, &$cellContent)
302 {
303 foreach ($element->childNodes as $child) {
304 if ($child instanceof DOMText) {
305 $domText = preg_replace('/\s+/u', ' ', trim($child->nodeValue));
306 if (is_string($cellContent)) {
307 // simply append the text if the cell content is a plain text string
308 $cellContent .= $domText;
309 }
310 // but if we have a rich text run instead, we need to append it correctly
311 // TODO
312 } elseif ($child instanceof DOMElement) {
313 $attributeArray = [];
314 foreach ($child->attributes as $attribute) {
315 $attributeArray[$attribute->name] = $attribute->value;
316 }
317
318 switch ($child->nodeName) {
319 case 'meta':
320 foreach ($attributeArray as $attributeName => $attributeValue) {
321 // Extract character set, so we can convert to UTF-8 if required
322 if ($attributeName === 'charset') {
323 $this->setInputEncoding($attributeValue);
324 }
325 }
326 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
327
328 break;
329 case 'title':
330 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
331 $sheet->setTitle($cellContent, true, false);
332 $cellContent = '';
333
334 break;
335 case 'span':
336 case 'div':
337 case 'font':
338 case 'i':
339 case 'em':
340 case 'strong':
341 case 'b':
342 if (isset($attributeArray['class']) && $attributeArray['class'] === 'comment') {
343 $sheet->getComment($column . $row)
344 ->getText()
345 ->createTextRun($child->textContent);
346
347 break;
348 }
349
350 if ($cellContent > '') {
351 $cellContent .= ' ';
352 }
353 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
354 if ($cellContent > '') {
355 $cellContent .= ' ';
356 }
357
358 if (isset($this->formats[$child->nodeName])) {
359 $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
360 }
361
362 break;
363 case 'hr':
364 $this->flushCell($sheet, $column, $row, $cellContent);
365 ++$row;
366 if (isset($this->formats[$child->nodeName])) {
367 $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
368 } else {
369 $cellContent = '----------';
370 $this->flushCell($sheet, $column, $row, $cellContent);
371 }
372 ++$row;
373 // Add a break after a horizontal rule, simply by allowing the code to dropthru
374 // no break
375 case 'br':
376 if ($this->tableLevel > 0) {
377 // If we're inside a table, replace with a \n
378 $cellContent .= "\n";
379 } else {
380 // Otherwise flush our existing content and move the row cursor on
381 $this->flushCell($sheet, $column, $row, $cellContent);
382 ++$row;
383 }
384
385 break;
386 case 'a':
387 foreach ($attributeArray as $attributeName => $attributeValue) {
388 switch ($attributeName) {
389 case 'href':
390 $sheet->getCell($column . $row)->getHyperlink()->setUrl($attributeValue);
391 if (isset($this->formats[$child->nodeName])) {
392 $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
393 }
394
395 break;
396 case 'class':
397 if ($attributeValue === 'comment-indicator') {
398 break; // Ignore - it's just a red square.
399 }
400 }
401 }
402 $cellContent .= ' ';
403 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
404
405 break;
406 case 'h1':
407 case 'h2':
408 case 'h3':
409 case 'h4':
410 case 'h5':
411 case 'h6':
412 case 'ol':
413 case 'ul':
414 case 'p':
415 if ($this->tableLevel > 0) {
416 // If we're inside a table, replace with a \n
417 $cellContent .= "\n";
418 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
419 } else {
420 if ($cellContent > '') {
421 $this->flushCell($sheet, $column, $row, $cellContent);
422 ++$row;
423 }
424 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
425 $this->flushCell($sheet, $column, $row, $cellContent);
426
427 if (isset($this->formats[$child->nodeName])) {
428 $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
429 }
430
431 ++$row;
432 $column = 'A';
433 }
434
435 break;
436 case 'li':
437 if ($this->tableLevel > 0) {
438 // If we're inside a table, replace with a \n
439 $cellContent .= "\n";
440 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
441 } else {
442 if ($cellContent > '') {
443 $this->flushCell($sheet, $column, $row, $cellContent);
444 }
445 ++$row;
446 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
447 $this->flushCell($sheet, $column, $row, $cellContent);
448 $column = 'A';
449 }
450
451 break;
452 case 'img':
453 $this->insertImage($sheet, $column, $row, $attributeArray);
454
455 break;
456 case 'table':
457 $this->flushCell($sheet, $column, $row, $cellContent);
458 $column = $this->setTableStartColumn($column);
459 if ($this->tableLevel > 1) {
460 --$row;
461 }
462 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
463 $column = $this->releaseTableStartColumn();
464 if ($this->tableLevel > 1) {
465 ++$column;
466 } else {
467 ++$row;
468 }
469
470 break;
471 case 'thead':
472 case 'tbody':
473 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
474
475 break;
476 case 'tr':
477 $column = $this->getTableStartColumn();
478 $cellContent = '';
479 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
480
481 if (isset($attributeArray['height'])) {
482 $sheet->getRowDimension($row)->setRowHeight($attributeArray['height']);
483 }
484
485 ++$row;
486
487 break;
488 case 'th':
489 case 'td':
490 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
491
492 // apply inline style
493 $this->applyInlineStyle($sheet, $row, $column, $attributeArray);
494
495 while (isset($this->rowspan[$column . $row])) {
496 ++$column;
497 }
498
499 $this->flushCell($sheet, $column, $row, $cellContent);
500
501 if (isset($attributeArray['rowspan'], $attributeArray['colspan'])) {
502 //create merging rowspan and colspan
503 $columnTo = $column;
504 for ($i = 0; $i < $attributeArray['colspan'] - 1; ++$i) {
505 ++$columnTo;
506 }
507 $range = $column . $row . ':' . $columnTo . ($row + $attributeArray['rowspan'] - 1);
508 foreach (Coordinate::extractAllCellReferencesInRange($range) as $value) {
509 $this->rowspan[$value] = true;
510 }
511 $sheet->mergeCells($range);
512 $column = $columnTo;
513 } elseif (isset($attributeArray['rowspan'])) {
514 //create merging rowspan
515 $range = $column . $row . ':' . $column . ($row + $attributeArray['rowspan'] - 1);
516 foreach (Coordinate::extractAllCellReferencesInRange($range) as $value) {
517 $this->rowspan[$value] = true;
518 }
519 $sheet->mergeCells($range);
520 } elseif (isset($attributeArray['colspan'])) {
521 //create merging colspan
522 $columnTo = $column;
523 for ($i = 0; $i < $attributeArray['colspan'] - 1; ++$i) {
524 ++$columnTo;
525 }
526 $sheet->mergeCells($column . $row . ':' . $columnTo . $row);
527 $column = $columnTo;
528 } elseif (isset($attributeArray['bgcolor'])) {
529 $sheet->getStyle($column . $row)->applyFromArray(
530 [
531 'fill' => [
532 'fillType' => Fill::FILL_SOLID,
533 'color' => ['rgb' => $attributeArray['bgcolor']],
534 ],
535 ]
536 );
537 }
538
539 if (isset($attributeArray['width'])) {
540 $sheet->getColumnDimension($column)->setWidth($attributeArray['width']);
541 }
542
543 if (isset($attributeArray['height'])) {
544 $sheet->getRowDimension($row)->setRowHeight($attributeArray['height']);
545 }
546
547 if (isset($attributeArray['align'])) {
548 $sheet->getStyle($column . $row)->getAlignment()->setHorizontal($attributeArray['align']);
549 }
550
551 if (isset($attributeArray['valign'])) {
552 $sheet->getStyle($column . $row)->getAlignment()->setVertical($attributeArray['valign']);
553 }
554
555 if (isset($attributeArray['data-format'])) {
556 $sheet->getStyle($column . $row)->getNumberFormat()->setFormatCode($attributeArray['data-format']);
557 }
558
559 ++$column;
560
561 break;
562 case 'body':
563 $row = 1;
564 $column = 'A';
565 $cellContent = '';
566 $this->tableLevel = 0;
567 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
568
569 break;
570 default:
571 $this->processDomElement($child, $sheet, $row, $column, $cellContent);
572 }
573 }
574 }
575 }
576
577 /**
578 * Loads PhpSpreadsheet from file into PhpSpreadsheet instance.
579 *
580 * @param string $pFilename
581 * @param Spreadsheet $spreadsheet
582 *
583 * @throws Exception
584 *
585 * @return Spreadsheet
586 */
587 public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
588 {
589 // Validate
590 if (!$this->canRead($pFilename)) {
591 throw new Exception($pFilename . ' is an Invalid HTML file.');
592 }
593
594 // Create new sheet
595 while ($spreadsheet->getSheetCount() <= $this->sheetIndex) {
596 $spreadsheet->createSheet();
597 }
598 $spreadsheet->setActiveSheetIndex($this->sheetIndex);
599
600 // Create a new DOM object
601 $dom = new DOMDocument();
602 // Reload the HTML file into the DOM object
603 $loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanner->scanFile($pFilename), 'HTML-ENTITIES', 'UTF-8'));
604 if ($loaded === false) {
605 throw new Exception('Failed to load ' . $pFilename . ' as a DOM Document');
606 }
607
608 // Discard white space
609 $dom->preserveWhiteSpace = false;
610
611 $row = 0;
612 $column = 'A';
613 $content = '';
614 $this->rowspan = [];
615 $this->processDomElement($dom, $spreadsheet->getActiveSheet(), $row, $column, $content);
616
617 // Return
618 return $spreadsheet;
619 }
620
621 /**
622 * Get sheet index.
623 *
624 * @return int
625 */
626 public function getSheetIndex()
627 {
628 return $this->sheetIndex;
629 }
630
631 /**
632 * Set sheet index.
633 *
634 * @param int $pValue Sheet index
635 *
636 * @return HTML
637 */
638 public function setSheetIndex($pValue)
639 {
640 $this->sheetIndex = $pValue;
641
642 return $this;
643 }
644
645 /**
646 * Apply inline css inline style.
647 *
648 * NOTES :
649 * Currently only intended for td & th element,
650 * and only takes 'background-color' and 'color'; property with HEX color
651 *
652 * TODO :
653 * - Implement to other propertie, such as border
654 *
655 * @param Worksheet $sheet
656 * @param int $row
657 * @param string $column
658 * @param array $attributeArray
659 */
660 private function applyInlineStyle(&$sheet, $row, $column, $attributeArray)
661 {
662 if (!isset($attributeArray['style'])) {
663 return;
664 }
665
666 $cellStyle = $sheet->getStyle($column . $row);
667
668 // add color styles (background & text) from dom element,currently support : td & th, using ONLY inline css style with RGB color
669 $styles = explode(';', $attributeArray['style']);
670 foreach ($styles as $st) {
671 $value = explode(':', $st);
672 $styleName = isset($value[0]) ? trim($value[0]) : null;
673 $styleValue = isset($value[1]) ? trim($value[1]) : null;
674
675 if (!$styleName) {
676 continue;
677 }
678
679 switch ($styleName) {
680 case 'background':
681 case 'background-color':
682 $styleColor = $this->getStyleColor($styleValue);
683
684 if (!$styleColor) {
685 continue 2;
686 }
687
688 $cellStyle->applyFromArray(['fill' => ['fillType' => Fill::FILL_SOLID, 'color' => ['rgb' => $styleColor]]]);
689
690 break;
691 case 'color':
692 $styleColor = $this->getStyleColor($styleValue);
693
694 if (!$styleColor) {
695 continue 2;
696 }
697
698 $cellStyle->applyFromArray(['font' => ['color' => ['rgb' => $styleColor]]]);
699
700 break;
701
702 case 'border':
703 $this->setBorderStyle($cellStyle, $styleValue, 'allBorders');
704
705 break;
706
707 case 'border-top':
708 $this->setBorderStyle($cellStyle, $styleValue, 'top');
709
710 break;
711
712 case 'border-bottom':
713 $this->setBorderStyle($cellStyle, $styleValue, 'bottom');
714
715 break;
716
717 case 'border-left':
718 $this->setBorderStyle($cellStyle, $styleValue, 'left');
719
720 break;
721
722 case 'border-right':
723 $this->setBorderStyle($cellStyle, $styleValue, 'right');
724
725 break;
726
727 case 'font-size':
728 $cellStyle->getFont()->setSize(
729 (float) $styleValue
730 );
731
732 break;
733
734 case 'font-weight':
735 if ($styleValue === 'bold' || $styleValue >= 500) {
736 $cellStyle->getFont()->setBold(true);
737 }
738
739 break;
740
741 case 'font-style':
742 if ($styleValue === 'italic') {
743 $cellStyle->getFont()->setItalic(true);
744 }
745
746 break;
747
748 case 'font-family':
749 $cellStyle->getFont()->setName(str_replace('\'', '', $styleValue));
750
751 break;
752
753 case 'text-decoration':
754 switch ($styleValue) {
755 case 'underline':
756 $cellStyle->getFont()->setUnderline(Font::UNDERLINE_SINGLE);
757
758 break;
759 case 'line-through':
760 $cellStyle->getFont()->setStrikethrough(true);
761
762 break;
763 }
764
765 break;
766
767 case 'text-align':
768 $cellStyle->getAlignment()->setHorizontal($styleValue);
769
770 break;
771
772 case 'vertical-align':
773 $cellStyle->getAlignment()->setVertical($styleValue);
774
775 break;
776
777 case 'width':
778 $sheet->getColumnDimension($column)->setWidth(
779 str_replace('px', '', $styleValue)
780 );
781
782 break;
783
784 case 'height':
785 $sheet->getRowDimension($row)->setRowHeight(
786 str_replace('px', '', $styleValue)
787 );
788
789 break;
790
791 case 'word-wrap':
792 $cellStyle->getAlignment()->setWrapText(
793 $styleValue === 'break-word'
794 );
795
796 break;
797
798 case 'text-indent':
799 $cellStyle->getAlignment()->setIndent(
800 (int) str_replace(['px'], '', $styleValue)
801 );
802
803 break;
804 }
805 }
806 }
807
808 /**
809 * Check if has #, so we can get clean hex.
810 *
811 * @param $value
812 *
813 * @return null|string
814 */
815 public function getStyleColor($value)
816 {
817 if (strpos($value, '#') === 0) {
818 return substr($value, 1);
819 }
820
821 return null;
822 }
823
824 /**
825 * @param Worksheet $sheet
826 * @param string $column
827 * @param int $row
828 * @param array $attributes
829 *
830 * @throws \PhpOffice\PhpSpreadsheet\Exception
831 */
832 private function insertImage(Worksheet $sheet, $column, $row, array $attributes)
833 {
834 if (!isset($attributes['src'])) {
835 return;
836 }
837
838 $src = urldecode($attributes['src']);
839 $width = isset($attributes['width']) ? (float) $attributes['width'] : null;
840 $height = isset($attributes['height']) ? (float) $attributes['height'] : null;
841 $name = isset($attributes['alt']) ? (float) $attributes['alt'] : null;
842
843 $drawing = new Drawing();
844 $drawing->setPath($src);
845 $drawing->setWorksheet($sheet);
846 $drawing->setCoordinates($column . $row);
847 $drawing->setOffsetX(0);
848 $drawing->setOffsetY(10);
849 $drawing->setResizeProportional(true);
850
851 if ($name) {
852 $drawing->setName($name);
853 }
854
855 if ($width) {
856 $drawing->setWidth((int) $width);
857 }
858
859 if ($height) {
860 $drawing->setHeight((int) $height);
861 }
862
863 $sheet->getColumnDimension($column)->setWidth(
864 $drawing->getWidth() / 6
865 );
866
867 $sheet->getRowDimension($row)->setRowHeight(
868 $drawing->getHeight() * 0.9
869 );
870 }
871
872 /**
873 * Map html border style to PhpSpreadsheet border style.
874 *
875 * @param string $style
876 *
877 * @return null|string
878 */
879 public function getBorderStyle($style)
880 {
881 switch ($style) {
882 case 'solid':
883 return Border::BORDER_THIN;
884 case 'dashed':
885 return Border::BORDER_DASHED;
886 case 'dotted':
887 return Border::BORDER_DOTTED;
888 case 'medium':
889 return Border::BORDER_MEDIUM;
890 case 'thick':
891 return Border::BORDER_THICK;
892 case 'none':
893 return Border::BORDER_NONE;
894 case 'dash-dot':
895 return Border::BORDER_DASHDOT;
896 case 'dash-dot-dot':
897 return Border::BORDER_DASHDOTDOT;
898 case 'double':
899 return Border::BORDER_DOUBLE;
900 case 'hair':
901 return Border::BORDER_HAIR;
902 case 'medium-dash-dot':
903 return Border::BORDER_MEDIUMDASHDOT;
904 case 'medium-dash-dot-dot':
905 return Border::BORDER_MEDIUMDASHDOTDOT;
906 case 'medium-dashed':
907 return Border::BORDER_MEDIUMDASHED;
908 case 'slant-dash-dot':
909 return Border::BORDER_SLANTDASHDOT;
910 }
911
912 return null;
913 }
914
915 /**
916 * @param Style $cellStyle
917 * @param string $styleValue
918 * @param string $type
919 */
920 private function setBorderStyle(Style $cellStyle, $styleValue, $type)
921 {
922 list(, $borderStyle, $color) = explode(' ', $styleValue);
923
924 $cellStyle->applyFromArray([
925 'borders' => [
926 $type => [
927 'borderStyle' => $this->getBorderStyle($borderStyle),
928 'color' => ['rgb' => $this->getStyleColor($color)],
929 ],
930 ],
931 ]);
932 }
933 }
934