PluginProbe
TablePress – Tables in WordPress made easy / 3.2
TablePress – Tables in WordPress made easy v3.2
3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.12 1.14 1.9.2 2.0.4 2.1.7 2.1.8 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3 2.3.1 2.3.2 2.4 2.4.1 2.4.2 2.4.3 2.4.4 All 44 releases
← All changes | libraries/simplexlsx.class.php +155 -179 2.23.2 View file →
@@ -1,9 +1,9 @@
1 1 <?php
2 2 /**
3 - * Excel 2007-2019/Office 365 Reader Class
3 + * Excel 2007-2019/Office 365 Reader class
4 4 *
5 - * Based on SimpleXLSX v1.0.19 by Sergey Shuchkin.
5 + * Based on SimpleXLSX v1.1.14 by Sergey Shuchkin.
6 6 * @link https://github.com/shuchkin/simplexlsx/
7 7 *
8 8 * @package TablePress
9 9 * @subpackage Import
@@ -15,9 +15,10 @@
15 15
16 16 use SimpleXMLElement;
17 17
18 18 /**
19 - * PHP Excel 2007-2013/Office 365 Reader Class
19 + * PHP Excel 2007-2013/Office 365 Reader class
20 + *
20 21 * @package TablePress
21 22 * @subpackage Import
22 23 * @author Sergey Shuchkin, Tobias Bäthge
23 24 * @since 1.1.0
@@ -78,18 +79,18 @@
78 79 public $activeSheet = 0;
79 80 public $rowsExReader;
80 81
81 82 /* @var SimpleXMLElement[] $sheets */
82 - protected $sheets;
83 - protected $sheetFiles = [];
84 - protected $sheetMetaData = [];
83 + public $sheets;
84 + public $sheetFiles = [];
85 + public $sheetMetaData = [];
86 + public $sheetRels = [];
85 87 // scheme
86 88 public $styles;
87 - protected $hyperlinks;
88 89 /* @var array[] $package */
89 - protected $package;
90 - protected $sharedstrings;
91 - protected $date1904 = 0;
90 + public $package;
91 + public $sharedstrings;
92 + public $date1904 = 0;
92 93
93 94
94 95 /*
95 96 private $date_formats = array(
@@ -128,10 +129,10 @@
128 129 0x2c => '$%1.2f', //"$#,##0.00;($#,##0.00)",
129 130 0x30 => '%1.0f'); //"##0.0E0";
130 131 // }}}
131 132 */
132 - protected $errno = 0;
133 - protected $error = false;
133 + public $errno = 0;
134 + public $error = false;
134 135 /**
135 136 * @var false|SimpleXMLElement
136 137 */
137 138 public $theme;
@@ -148,20 +149,20 @@
148 149 'size' => 0,
149 150 'comment' => '',
150 151 'entries' => []
151 152 ];
152 - if ($filename && $this->_unzip($filename, $is_data)) {
153 - $this->_parse();
153 + if ($filename && $this->unzip($filename, $is_data)) {
154 + $this->parseEntries();
154 155 }
155 156 }
156 157
157 - protected function _unzip($filename, $is_data = false)
158 + public function unzip($filename, $is_data = false)
158 159 {
159 160
160 161 if ($is_data) {
161 162 $this->package['filename'] = 'default.xlsx';
162 163 $this->package['mtime'] = time();
163 - $this->package['size'] = $this->_strlen($filename);
164 + $this->package['size'] = self::strlen($filename);
164 165
165 166 $vZ = $filename;
166 167 } else {
167 168 if (!is_readable($filename)) {
@@ -229,25 +230,25 @@
229 230 $mF = $aP['EFL'];
230 231
231 232 // Special case : value block after the compressed data
232 233 if ($aP['GPF'] & 0x0008) {
233 - $aP1 = unpack('V1CRC/V1CS/V1UCS', $this->_substr($vZ, -12));
234 + $aP1 = unpack('V1CRC/V1CS/V1UCS', self::substr($vZ, -12));
234 235
235 236 $aP['CRC'] = $aP1['CRC'];
236 237 $aP['CS'] = $aP1['CS'];
237 238 $aP['UCS'] = $aP1['UCS'];
238 239 // 2013-08-10
239 - $vZ = $this->_substr($vZ, 0, -12);
240 - if ($this->_substr($vZ, -4) === "\x50\x4b\x07\x08") {
241 - $vZ = $this->_substr($vZ, 0, -4);
240 + $vZ = self::substr($vZ, 0, -12);
241 + if (self::substr($vZ, -4) === "\x50\x4b\x07\x08") {
242 + $vZ = self::substr($vZ, 0, -4);
242 243 }
243 244 }
244 245
245 246 // Getting stored filename
246 - $aI['N'] = $this->_substr($vZ, 26, $nF);
247 + $aI['N'] = self::substr($vZ, 26, $nF);
247 248 $aI['N'] = str_replace('\\', '/', $aI['N']);
248 249
249 - if ($this->_substr($aI['N'], -1) === '/') {
250 + if (self::substr($aI['N'], -1) === '/') {
250 251 // is a directory entry - will be skipped
251 252 continue;
252 253 }
253 254
@@ -255,11 +256,11 @@
255 256 $aI['P'] = dirname($aI['N']);
256 257 $aI['P'] = ($aI['P'] === '.') ? '' : $aI['P'];
257 258 $aI['N'] = basename($aI['N']);
258 259
259 - $vZ = $this->_substr($vZ, 26 + $nF + $mF);
260 + $vZ = self::substr($vZ, 26 + $nF + $mF);
260 261
261 - if ($this->_strlen($vZ) !== (int)$aP['CS']) { // check only if availabled
262 + if ($aP['CS'] > 0 && (self::strlen($vZ) !== (int)$aP['CS'])) { // check only if availabled
262 263 $aI['E'] = 1;
263 264 $aI['EM'] = 'Compressed size is not equal with the value in header information.';
264 265 }
265 266 // } elseif ( $bE ) {
@@ -326,12 +327,8 @@
326 327
327 328 return true;
328 329 }
329 330
330 - protected function _strlen($str)
331 - {
332 - return (ini_get('mbstring.func_overload') & 2) ? mb_strlen($str, '8bit') : strlen($str);
333 - }
334 331
335 332 public function error($num = null, $str = null)
336 333 {
337 334 if ($num) {
@@ -344,15 +341,10 @@
344 341
345 342 return $this->error;
346 343 }
347 344
348 - protected function _substr($str, $start, $length = null)
345 + public function parseEntries()
349 346 {
350 - return (ini_get('mbstring.func_overload') & 2) ? mb_substr($str, $start, ($length === null) ? mb_strlen($str, '8bit') : $length, '8bit') : substr($str, $start, ($length === null) ? strlen($str) : $length);
351 - }
352 -
353 - protected function _parse()
354 - {
355 347 // Document data holders
356 348 $this->sharedstrings = [];
357 349 $this->sheets = [];
358 350 // $this->styles = array();
@@ -360,11 +352,13 @@
360 352 // Read relations and search for officeDocument
361 353 if ($relations = $this->getEntryXML('_rels/.rels')) {
362 354 foreach ($relations->Relationship as $rel) {
363 355 $rel_type = basename(trim((string)$rel['Type'])); // officeDocument
364 - $rel_target = $this->_getTarget('', (string)$rel['Target']); // /xl/workbook.xml or xl/workbook.xml
356 + $rel_target = self::getTarget('', (string)$rel['Target']); // /xl/workbook.xml or xl/workbook.xml
365 357
366 - if ($rel_type === 'officeDocument' && $workbook = $this->getEntryXML($rel_target)) {
358 + if ($rel_type === 'officeDocument'
359 + && $workbook = $this->getEntryXML($rel_target)
360 + ) {
367 361 $index_rId = []; // [0 => rId1]
368 362
369 363 $index = 0;
370 364 foreach ($workbook->sheets->sheet as $s) {
@@ -384,32 +378,37 @@
384 378 if ($workbookRelations = $this->getEntryXML(dirname($rel_target) . '/_rels/workbook.xml.rels')) {
385 379 // Loop relations for workbook and extract sheets...
386 380 foreach ($workbookRelations->Relationship as $workbookRelation) {
387 381 $wrel_type = basename(trim((string)$workbookRelation['Type'])); // worksheet
388 - $wrel_path = $this->_getTarget(dirname($rel_target), (string)$workbookRelation['Target']);
389 - if (!$this->entryExists($wrel_path)) {
382 + $wrel_target = self::getTarget(dirname($rel_target), (string)$workbookRelation['Target']);
383 + if (!$this->entryExists($wrel_target)) {
390 384 continue;
391 385 }
392 386
393 -
394 387 if ($wrel_type === 'worksheet') { // Sheets
395 - if ($sheet = $this->getEntryXML($wrel_path)) {
388 + if ($sheet = $this->getEntryXML($wrel_target)) {
396 389 $index = array_search((string)$workbookRelation['Id'], $index_rId, true);
397 390 $this->sheets[$index] = $sheet;
398 - $this->sheetFiles[$index] = $wrel_path;
391 + $this->sheetFiles[$index] = $wrel_target;
392 + $srel_d = dirname($wrel_target);
393 + $srel_f = basename($wrel_target);
394 + $srel_file = $srel_d . '/_rels/' . $srel_f . '.rels';
395 + if ($this->entryExists($srel_file)) {
396 + $this->sheetRels[$index] = $this->getEntryXML($srel_file);
397 + }
399 398 }
400 399 } elseif ($wrel_type === 'sharedStrings') {
401 - if ($sharedStrings = $this->getEntryXML($wrel_path)) {
400 + if ($sharedStrings = $this->getEntryXML($wrel_target)) {
402 401 foreach ($sharedStrings->si as $val) {
403 402 if (isset($val->t)) {
404 403 $this->sharedstrings[] = (string)$val->t;
405 404 } elseif (isset($val->r)) {
406 - $this->sharedstrings[] = $this->_parseRichText($val);
405 + $this->sharedstrings[] = self::parseRichText($val);
407 406 }
408 407 }
409 408 }
410 409 } elseif ($wrel_type === 'styles') {
411 - $this->styles = $this->getEntryXML($wrel_path);
410 + $this->styles = $this->getEntryXML($wrel_target);
412 411
413 412 // number formats
414 413 $this->nf = [];
415 414 if (isset($this->styles->numFmts->numFmt)) {
@@ -438,20 +437,24 @@
438 437 $this->cellFormats[] = $x;
439 438 }
440 439 }
441 440 } elseif ($wrel_type === 'theme') {
442 - $this->theme = $this->getEntryXML($wrel_path);
441 + $this->theme = $this->getEntryXML($wrel_target);
443 442 }
444 443 }
445 444
446 - break;
445 +// break;
447 446 }
448 447 // reptile hack :: find active sheet from workbook.xml
449 - foreach ($workbook->bookViews->workbookView as $s) {
450 - if (!empty($s['activeTab'])) {
451 - $this->activeSheet = (int)$s['activeTab'];
448 + if ($workbook->bookViews->workbookView) {
449 + foreach ($workbook->bookViews->workbookView as $v) {
450 + if (!empty($v['activeTab'])) {
451 + $this->activeSheet = (int)$v['activeTab'];
452 + }
452 453 }
453 454 }
455 +
456 + break;
454 457 }
455 458 }
456 459 }
457 460
@@ -474,9 +477,10 @@
474 477 $this->deleteEntry($name); // economy memory
475 478 // dirty remove namespace prefixes and empty rows
476 479 $entry_xml = preg_replace('/xmlns[^=]*="[^"]*"/i', '', $entry_xml); // remove namespaces
477 480 $entry_xml .= ' '; // force run garbage collector
478 - $entry_xml = preg_replace('/[a-zA-Z0-9]+:([a-zA-Z0-9]+="[^"]+")/', '$1', $entry_xml); // remove namespaced attrs
481 + // remove namespaced attrs
482 + $entry_xml = preg_replace('/[a-zA-Z0-9]+:([a-zA-Z0-9]+="[^"]+")/', '$1', $entry_xml);
479 483 $entry_xml .= ' ';
480 484 $entry_xml = preg_replace('/<[a-zA-Z0-9]+:([^>]+)>/', '<$1>', $entry_xml); // fix namespaced openned tags
481 485 $entry_xml .= ' ';
482 486 $entry_xml = preg_replace('/<\/[a-zA-Z0-9]+:([^>]+)>/', '</$1>', $entry_xml); // fix namespaced closed tags
@@ -538,12 +542,12 @@
538 542
539 543 public function getEntryData($name)
540 544 {
541 545 $name = ltrim(str_replace('\\', '/', $name), '/');
542 - $dir = $this->_strtoupper(dirname($name));
543 - $name = $this->_strtoupper(basename($name));
546 + $dir = self::strtoupper(dirname($name));
547 + $name = self::strtoupper(basename($name));
544 548 foreach ($this->package['entries'] as &$entry) {
545 - if ($this->_strtoupper($entry['path']) === $dir && $this->_strtoupper($entry['name']) === $name) {
549 + if (self::strtoupper($entry['path']) === $dir && self::strtoupper($entry['name']) === $name) {
546 550 if ($entry['error']) {
547 551 return false;
548 552 }
549 553 switch ($entry['cm']) {
@@ -570,9 +574,9 @@
570 574 $entry['cm'] = -1;
571 575 if ($entry['data'] === false) {
572 576 $entry['error'] = 2;
573 577 $entry['error_msg'] = 'Decompression of data failed.';
574 - } elseif ($this->_strlen($entry['data']) !== (int)$entry['ucs']) {
578 + } elseif ($entry['ucs'] > 0 && (self::strlen($entry['data']) !== (int)$entry['ucs'])) {
575 579 $entry['error'] = 3;
576 580 $entry['error_msg'] = 'Uncompressed size is not equal with the value in header information.';
577 581 } elseif (crc32($entry['data']) !== $entry['crc']) {
578 582 $entry['error'] = 4;
@@ -590,12 +594,12 @@
590 594 }
591 595 public function deleteEntry($name)
592 596 {
593 597 $name = ltrim(str_replace('\\', '/', $name), '/');
594 - $dir = $this->_strtoupper(dirname($name));
595 - $name = $this->_strtoupper(basename($name));
598 + $dir = self::strtoupper(dirname($name));
599 + $name = self::strtoupper(basename($name));
596 600 foreach ($this->package['entries'] as $k => $entry) {
597 - if ($this->_strtoupper($entry['path']) === $dir && $this->_strtoupper($entry['name']) === $name) {
601 + if (self::strtoupper($entry['path']) === $dir && self::strtoupper($entry['name']) === $name) {
598 602 unset($this->package['entries'][$k]);
599 603 return true;
600 604 }
601 605 }
@@ -601,36 +605,13 @@
601 605 }
602 606 return false;
603 607 }
604 608
605 - protected function _strtoupper($str)
609 + public static function strtoupper($str)
606 610 {
607 611 return (ini_get('mbstring.func_overload') & 2) ? mb_strtoupper($str, '8bit') : strtoupper($str);
608 612 }
609 613
610 - protected function _getTarget($base, $target)
611 - {
612 - $target = trim($target);
613 - if (strpos($target, '/') === 0) {
614 - return $this->_substr($target, 1);
615 - }
616 - $target = ($base ? $base . '/' : '') . $target;
617 - // a/b/../c -> a/c
618 - $parts = explode('/', $target);
619 - $abs = [];
620 - foreach ($parts as $p) {
621 - if ('.' === $p) {
622 - continue;
623 - }
624 - if ('..' === $p) {
625 - array_pop($abs);
626 - } else {
627 - $abs[] = $p;
628 - }
629 - }
630 - return implode('/', $abs);
631 - }
632 -
633 614 /*
634 615 * @param string $name Filename in archive
635 616 * @return SimpleXMLElement|bool
636 617 */
@@ -637,12 +618,12 @@
637 618
638 619 public function entryExists($name)
639 620 {
640 621 // 0.6.6
641 - $dir = $this->_strtoupper(dirname($name));
642 - $name = $this->_strtoupper(basename($name));
622 + $dir = self::strtoupper(dirname($name));
623 + $name = self::strtoupper(basename($name));
643 624 foreach ($this->package['entries'] as $entry) {
644 - if ($this->_strtoupper($entry['path']) === $dir && $this->_strtoupper($entry['name']) === $name) {
625 + if (self::strtoupper($entry['path']) === $dir && self::strtoupper($entry['name']) === $name) {
645 626 return true;
646 627 }
647 628 }
648 629
@@ -648,23 +629,8 @@
648 629
649 630 return false;
650 631 }
651 632
652 - protected function _parseRichText($is = null)
653 - {
654 - $value = [];
655 -
656 - if (isset($is->t)) {
657 - $value[] = (string)$is->t;
658 - } elseif (isset($is->r)) {
659 - foreach ($is->r as $run) {
660 - $value[] = (string)$run->t;
661 - }
662 - }
663 -
664 - return implode('', $value);
665 - }
666 -
667 633 public static function parseFile($filename, $debug = false)
668 634 {
669 635 return self::parse($filename, false, $debug);
670 636 }
@@ -672,10 +638,10 @@
672 638 public static function parse($filename, $is_data = false, $debug = false)
673 639 {
674 640 $xlsx = new self();
675 641 $xlsx->debug = $debug;
676 - if ($xlsx->_unzip($filename, $is_data)) {
677 - $xlsx->_parse();
642 + if ($xlsx->unzip($filename, $is_data)) {
643 + $xlsx->parseEntries();
678 644 }
679 645 if ($xlsx->success()) {
680 646 return $xlsx;
681 647 }
@@ -719,49 +685,10 @@
719 685
720 686
721 687 public function worksheet($worksheetIndex = 0)
722 688 {
723 -
724 -
725 689 if (isset($this->sheets[$worksheetIndex])) {
726 - $ws = $this->sheets[$worksheetIndex];
727 -
728 - if (!isset($this->hyperlinks[$worksheetIndex]) && isset($ws->hyperlinks)) {
729 - $this->hyperlinks[$worksheetIndex] = [];
730 - $sheet_rels = str_replace('worksheets', 'worksheets/_rels', $this->sheetFiles[$worksheetIndex]) . '.rels';
731 - $link_ids = [];
732 -
733 - if ($rels = $this->getEntryXML($sheet_rels)) {
734 - // hyperlink
735 -// $rel_base = dirname( $sheet_rels );
736 - foreach ($rels->Relationship as $rel) {
737 - $rel_type = basename(trim((string)$rel['Type']));
738 - if ($rel_type === 'hyperlink') {
739 - $rel_id = (string)$rel['Id'];
740 - $rel_target = (string)$rel['Target'];
741 - $link_ids[$rel_id] = $rel_target;
742 - }
743 - }
744 - }
745 - foreach ($ws->hyperlinks->hyperlink as $hyperlink) {
746 - $ref = (string)$hyperlink['ref'];
747 - if ($this->_strpos($ref, ':') > 0) { // A1:A8 -> A1
748 - $ref = explode(':', $ref);
749 - $ref = $ref[0];
750 - }
751 -// $this->hyperlinks[ $worksheetIndex ][ $ref ] = (string) $hyperlink['display'];
752 - $loc = (string)$hyperlink['location'];
753 - $id = (string)$hyperlink['id'];
754 - if ($id) {
755 - $href = $link_ids[$id] . ($loc ? '#' . $loc : '');
756 - } else {
757 - $href = $loc;
758 - }
759 - $this->hyperlinks[$worksheetIndex][$ref] = $href;
760 - }
761 - }
762 -
763 - return $ws;
690 + return $this->sheets[$worksheetIndex];
764 691 }
765 692 $this->error(6, 'Worksheet not found ' . $worksheetIndex);
766 693
767 694 return false;
@@ -766,13 +693,8 @@
766 693
767 694 return false;
768 695 }
769 696
770 - protected function _strpos($haystack, $needle, $offset = 0)
771 - {
772 - return (ini_get('mbstring.func_overload') & 2) ? mb_strpos($haystack, $needle, $offset, '8bit') : strpos($haystack, $needle, $offset);
773 - }
774 -
775 697 /**
776 698 * returns [numCols,numRows] of worksheet
777 699 *
778 700 * @param int $worksheetIndex
@@ -788,9 +710,9 @@
788 710 /* @var SimpleXMLElement $ws */
789 711
790 712 $ref = (string)$ws->dimension['ref'];
791 713
792 - if ($this->_strpos($ref, ':') !== false) {
714 + if (self::strpos($ref, ':') !== false) {
793 715 $d = explode(':', $ref);
794 716 $idx = $this->getIndex($d[1]);
795 717
796 718 return [$idx[0] + 1, $idx[1] + 1];
@@ -841,9 +763,9 @@
841 763 if (preg_match('/([A-Z]+)(\d+)/', $cell, $m)) {
842 764 $col = $m[1];
843 765 $row = $m[2];
844 766
845 - $colLen = $this->_strlen($col);
767 + $colLen = self::strlen($col);
846 768 $index = 0;
847 769
848 770 for ($i = $colLen - 1; $i >= 0; $i--) {
849 771 $index += (ord($col[$i]) - 64) * pow(26, $colLen - $i - 1);
@@ -866,9 +788,9 @@
866 788 $s = (int)$cell['s'];
867 789 if ($s > 0 && isset($this->cellFormats[$s])) {
868 790 if (array_key_exists('format', $this->cellFormats[$s])) {
869 791 $format = $this->cellFormats[$s]['format'];
870 - if (preg_match('/[mM]/', preg_replace('/\"[^"]+\"/', '', $format))) { // [mm]onth,AM|PM
792 + if ($format && preg_match('/[mM]/', preg_replace('/\"[^"]+\"/', '', $format))) { // [mm]onth,AM|PM
871 793 $dataType = 'D';
872 794 }
873 795 } else {
874 796 $dataType = 'n';
@@ -893,22 +815,15 @@
893 815 break;
894 816
895 817 case 'b':
896 818 // Value is boolean
897 - $value = (string)$cell->v;
898 - if ($value === '0') {
899 - $value = false;
900 - } elseif ($value === '1') {
901 - $value = true;
902 - } else {
903 - $value = (bool)$cell->v;
904 - }
819 + $value = self::boolean((string)$cell->v);
905 820
906 821 break;
907 822
908 823 case 'inlineStr':
909 824 // Value is rich text inline
910 - $value = $this->_parseRichText($cell->is);
825 + $value = self::parseRichText($cell->is);
911 826
912 827 break;
913 828
914 829 case 'e':
@@ -920,9 +835,10 @@
920 835
921 836 case 'D':
922 837 // Date as float
923 838 if (!empty($cell->v)) {
924 - $value = $this->datetimeFormat ? gmdate($this->datetimeFormat, $this->unixstamp((float)$cell->v)) : (float)$cell->v;
839 + $value = $this->datetimeFormat ?
840 + gmdate($this->datetimeFormat, $this->unixstamp((float)$cell->v)) : (float)$cell->v;
925 841 }
926 842 break;
927 843
928 844 case 'd':
@@ -964,14 +880,8 @@
964 880
965 881 return (int)$t;
966 882 }
967 883
968 - public function href($worksheetIndex, $cell)
969 - {
970 - $ref = (string)$cell['r'];
971 - return isset($this->hyperlinks[$worksheetIndex][$ref]) ? $this->hyperlinks[$worksheetIndex][$ref] : '';
972 - }
973 -
974 884 public function toHTML($worksheetIndex = 0)
975 885 {
976 886 $s = '<table class=excel>';
977 887 foreach ($this->readRows($worksheetIndex) as $r) {
@@ -1002,9 +912,10 @@
1002 912
1003 913 if ($x === 0 && $c['height']) {
1004 914 $css .= 'height: '.round($c['height'] * 1.3333).'px;';
1005 915 }
1006 - $s .= '<'.$tag.' style="'.$css.'" nowrap>' . ($c['value'] === '' ? '&nbsp' : htmlspecialchars($c['value'], ENT_QUOTES)) . '</'.$tag.'>';
916 + $s .= '<'.$tag.' style="'.$css.'" nowrap>'
917 + . ($c['value'] === '' ? '&nbsp' : htmlspecialchars($c['value'], ENT_QUOTES)) . '</'.$tag.'>';
1007 918 $x++;
1008 919 }
1009 920 $s .= "</tr>\r\n";
1010 921 $y++;
@@ -1116,9 +1027,9 @@
1116 1027 if (($ws = $this->worksheet($worksheetIndex)) === false) {
1117 1028 return false;
1118 1029 }
1119 1030 if (is_array($cell)) {
1120 - $cell = $this->_num2name($cell[0]) . $cell[1];// [3,21] -> D21
1031 + $cell = self::num2name($cell[0]) . $cell[1];// [3,21] -> D21
1121 1032 }
1122 1033 if (is_string($cell)) {
1123 1034 $result = $ws->sheetData->xpath("row/c[@r='" . $cell . "']");
1124 1035 if (count($result)) {
@@ -1128,19 +1039,8 @@
1128 1039
1129 1040 return null;
1130 1041 }
1131 1042
1132 - protected function _num2name($num)
1133 - {
1134 - $numeric = ($num - 1) % 26;
1135 - $letter = chr(65 + $numeric);
1136 - $num2 = (int)(($num - 1) / 26);
1137 - if ($num2 > 0) {
1138 - return $this->_num2name($num2) . $letter;
1139 - }
1140 - return $letter;
1141 - }
1142 -
1143 1043 public function getSheets()
1144 1044 {
1145 1045 return $this->sheets;
1146 1046 }
@@ -1176,9 +1076,10 @@
1176 1076 return isset($this->sheetMetaData[$worksheetIndex]) ? $this->sheetMetaData[$worksheetIndex] : false;
1177 1077 }
1178 1078 public function isHiddenSheet($worksheetIndex)
1179 1079 {
1180 - return isset($this->sheetMetaData[$worksheetIndex]['state']) && $this->sheetMetaData[$worksheetIndex]['state'] === 'hidden';
1080 + return isset($this->sheetMetaData[$worksheetIndex]['state'])
1081 + && $this->sheetMetaData[$worksheetIndex]['state'] === 'hidden';
1181 1082 }
1182 1083
1183 1084 public function getStyles()
1184 1085 {
@@ -1192,6 +1093,81 @@
1192 1093
1193 1094 public function setDateTimeFormat($value)
1194 1095 {
1195 1096 $this->datetimeFormat = is_string($value) ? $value : false;
1097 + }
1098 +
1099 + public static function getTarget($base, $target)
1100 + {
1101 + $target = trim($target);
1102 + if (strpos($target, '/') === 0) {
1103 + return self::substr($target, 1);
1104 + }
1105 + $target = ($base ? $base . '/' : '') . $target;
1106 + // a/b/../c -> a/c
1107 + $parts = explode('/', $target);
1108 + $abs = [];
1109 + foreach ($parts as $p) {
1110 + if ('.' === $p) {
1111 + continue;
1112 + }
1113 + if ('..' === $p) {
1114 + array_pop($abs);
1115 + } else {
1116 + $abs[] = $p;
1117 + }
1118 + }
1119 + return implode('/', $abs);
1120 + }
1121 +
1122 + public static function parseRichText($is = null)
1123 + {
1124 + $value = [];
1125 +
1126 + if (isset($is->t)) {
1127 + $value[] = (string)$is->t;
1128 + } elseif (isset($is->r)) {
1129 + foreach ($is->r as $run) {
1130 + $value[] = (string)$run->t;
1131 + }
1132 + }
1133 +
1134 + return implode('', $value);
1135 + }
1136 +
1137 + public static function num2name($num)
1138 + {
1139 + $numeric = ($num - 1) % 26;
1140 + $letter = chr(65 + $numeric);
1141 + $num2 = (int)(($num - 1) / 26);
1142 + if ($num2 > 0) {
1143 + return self::num2name($num2) . $letter;
1144 + }
1145 + return $letter;
1146 + }
1147 +
1148 + public static function strlen($str)
1149 + {
1150 + return (ini_get('mbstring.func_overload') & 2) ? mb_strlen($str, '8bit') : strlen($str);
1151 + }
1152 +
1153 + public static function substr($str, $start, $length = null)
1154 + {
1155 + return (ini_get('mbstring.func_overload') & 2) ?
1156 + mb_substr($str, $start, ($length === null) ? mb_strlen($str, '8bit') : $length, '8bit')
1157 + : substr($str, $start, ($length === null) ? strlen($str) : $length);
1158 + }
1159 +
1160 + public static function strpos($haystack, $needle, $offset = 0)
1161 + {
1162 + return (ini_get('mbstring.func_overload') & 2) ?
1163 + mb_strpos($haystack, $needle, $offset, '8bit') : strpos($haystack, $needle, $offset);
1164 + }
1165 + public static function boolean($value)
1166 + {
1167 + if (is_numeric($value)) {
1168 + return (bool) $value;
1169 + }
1170 +
1171 + return $value === 'true' || $value === 'TRUE';
1196 1172 }
1197 1173 }