| @@ -99,8 +99,14 @@ | ||
| 99 | 99 | */ |
| 100 | 100 | protected Worksheet $phpSheet; |
| 101 | 101 | |
| 102 | 102 | /** |
| 103 | + * Cached sheet title for the current sheet being parsed. | |
| 104 | + * Avoids repeated getTitle() calls in per-cell read filter checks. | |
| 105 | + */ | |
| 106 | + protected string $phpSheetTitle = ''; | |
| 107 | + | |
| 108 | + /** | |
| 103 | 109 | * BIFF version. |
| 104 | 110 | */ |
| 105 | 111 | protected int $version = 0; |
| 106 | 112 | |
| @@ -379,9 +385,9 @@ | ||
| 379 | 385 | $ole = new OLERead(); |
| 380 | 386 | // get excel data, |
| 381 | 387 | $ole->read($filename); |
| 382 | 388 | // Get workbook data: workbook stream + sheet streams |
| 383 | - $this->data = $ole->getStream($ole->wrkbook); // @phpstan-ignore-line | |
| 389 | + $this->data = $ole->getStream($ole->wrkbook) ?? ''; | |
| 384 | 390 | // Get summary information data |
| 385 | 391 | $this->summaryInformation = $ole->getStream($ole->summaryInformation); |
| 386 | 392 | // Get additional document summary information data |
| 387 | 393 | $this->documentSummaryInformation = $ole->getStream($ole->documentSummaryInformation); |
| @@ -1950,9 +1956,9 @@ | ||
| 1950 | 1956 | /** @var string $recordData */ |
| 1951 | 1957 | $nm = self::getInt4d($recordData, 4); |
| 1952 | 1958 | $pos += 4; |
| 1953 | 1959 | |
| 1954 | - // look up limit position | |
| 1960 | + // look up limit position (last splice offset where pos fits) | |
| 1955 | 1961 | foreach ($spliceOffsets as $spliceOffset) { |
| 1956 | 1962 | // it can happen that the string is empty, therefore we need |
| 1957 | 1963 | // <= and not just < |
| 1958 | 1964 | if ($pos <= $spliceOffset) { |
| @@ -1998,9 +2004,9 @@ | ||
| 1998 | 2004 | |
| 1999 | 2005 | // expected byte length of character array if not split |
| 2000 | 2006 | $len = ($isCompressed) ? $numChars : $numChars * 2; |
| 2001 | 2007 | |
| 2002 | - // look up limit position - Check it again to be sure that no error occurs when parsing SST structure | |
| 2008 | + // look up limit position - find the first splice offset at or beyond current pos | |
| 2003 | 2009 | $limitpos = null; |
| 2004 | 2010 | foreach ($spliceOffsets as $spliceOffset) { |
| 2005 | 2011 | // it can happen that the string is empty, therefore we need |
| 2006 | 2012 | // <= and not just < |
| @@ -2031,9 +2037,9 @@ | ||
| 2031 | 2037 | $pos = $limitpos; |
| 2032 | 2038 | |
| 2033 | 2039 | // keep reading the characters |
| 2034 | 2040 | while ($charsLeft > 0) { |
| 2035 | - // look up next limit position, in case the string span more than one continue record | |
| 2041 | + // look up next limit position, in case the string spans more than one continue record | |
| 2036 | 2042 | foreach ($spliceOffsets as $spliceOffset) { |
| 2037 | 2043 | if ($pos < $spliceOffset) { |
| 2038 | 2044 | $limitpos = $spliceOffset; |
| 2039 | 2045 | |
| @@ -2066,24 +2072,18 @@ | ||
| 2066 | 2072 | $isCompressed = false; |
| 2067 | 2073 | } elseif (!$isCompressed /*&& ($option == 0)*/) { |
| 2068 | 2074 | // 1st fragment uncompressed |
| 2069 | 2075 | // this fragment compressed |
| 2070 | - $len = min($charsLeft, $limitpos - $pos); | |
| 2071 | - for ($j = 0; $j < $len; ++$j) { | |
| 2072 | - $retstr .= $recordData[$pos + $j] | |
| 2073 | - . chr(0); | |
| 2074 | - } | |
| 2076 | + $len = (int) min($charsLeft, $limitpos - $pos); | |
| 2077 | + // Pad each byte with a null byte to expand to UTF-16LE | |
| 2078 | + $retstr .= chunk_split((string) substr($recordData, $pos, $len), 1, "\x00"); | |
| 2075 | 2079 | $charsLeft -= $len; |
| 2076 | 2080 | $isCompressed = false; |
| 2077 | 2081 | } else { |
| 2078 | 2082 | // 1st fragment compressed |
| 2079 | 2083 | // this fragment uncompressed |
| 2080 | - $newstr = ''; | |
| 2081 | - $jMax = strlen($retstr); | |
| 2082 | - for ($j = 0; $j < $jMax; ++$j) { | |
| 2083 | - $newstr .= $retstr[$j] . chr(0); | |
| 2084 | - } | |
| 2085 | - $retstr = $newstr; | |
| 2084 | + // Pad existing compressed string bytes with null bytes | |
| 2085 | + $retstr = chunk_split($retstr, 1, "\x00"); | |
| 2086 | 2086 | /** @var int */ |
| 2087 | 2087 | $len = min($charsLeft * 2, $limitpos - $pos); |
| 2088 | 2088 | $retstr .= substr($recordData, $pos, $len); |
| 2089 | 2089 | $charsLeft -= $len / 2; |
| @@ -2732,11 +2732,12 @@ | ||
| 2732 | 2732 | |
| 2733 | 2733 | // offset: 2; size: 2; index to column |
| 2734 | 2734 | $column = self::getUInt2d($recordData, 2); |
| 2735 | 2735 | $columnString = Coordinate::stringFromColumnIndex($column + 1); |
| 2736 | + $cellCoordinate = $columnString . ($row + 1); | |
| 2736 | 2737 | |
| 2737 | 2738 | // Read cell? |
| 2738 | - if ($this->readFilter->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) { | |
| 2739 | + if ($this->readFilter->readCell($columnString, $row + 1, $this->phpSheetTitle)) { | |
| 2739 | 2740 | // offset: 4; size: 2; index to XF record |
| 2740 | 2741 | $xfIndex = self::getUInt2d($recordData, 4); |
| 2741 | 2742 | |
| 2742 | 2743 | // offset: 6; size: 4; RK value |
| @@ -2742,12 +2743,12 @@ | ||
| 2742 | 2743 | // offset: 6; size: 4; RK value |
| 2743 | 2744 | $rknum = self::getInt4d($recordData, 6); |
| 2744 | 2745 | $numValue = self::getIEEE754($rknum); |
| 2745 | 2746 | |
| 2746 | - $cell = $this->phpSheet->getCell($columnString . ($row + 1)); | |
| 2747 | + $cell = $this->phpSheet->getCell($cellCoordinate); | |
| 2747 | 2748 | if (!$this->readDataOnly && isset($this->mapCellXfIndex[$xfIndex])) { |
| 2748 | 2749 | // add style information |
| 2749 | - $cell->setXfIndex($this->mapCellXfIndex[$xfIndex]); | |
| 2750 | + $cell->setXfIndexNoUpdate($this->mapCellXfIndex[$xfIndex]); | |
| 2750 | 2751 | } |
| 2751 | 2752 | |
| 2752 | 2753 | // add cell |
| 2753 | 2754 | $cell->setValueExplicit($numValue, DataType::TYPE_NUMERIC); |
| @@ -2776,12 +2777,12 @@ | ||
| 2776 | 2777 | |
| 2777 | 2778 | // offset: 2; size: 2; index to column |
| 2778 | 2779 | $column = self::getUInt2d($recordData, 2); |
| 2779 | 2780 | $columnString = Coordinate::stringFromColumnIndex($column + 1); |
| 2781 | + $cellCoordinate = $columnString . ($row + 1); | |
| 2780 | 2782 | |
| 2781 | - $cell = null; | |
| 2782 | 2783 | // Read cell? |
| 2783 | - if ($this->readFilter->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) { | |
| 2784 | + if ($this->readFilter->readCell($columnString, $row + 1, $this->phpSheetTitle)) { | |
| 2784 | 2785 | // offset: 4; size: 2; index to XF record |
| 2785 | 2786 | $xfIndex = self::getUInt2d($recordData, 4); |
| 2786 | 2787 | |
| 2787 | 2788 | // offset: 6; size: 4; index to SST record |
| @@ -2786,14 +2787,20 @@ | ||
| 2786 | 2787 | |
| 2787 | 2788 | // offset: 6; size: 4; index to SST record |
| 2788 | 2789 | $index = self::getInt4d($recordData, 6); |
| 2789 | 2790 | |
| 2791 | + // cache SST entry locally to avoid repeated array lookups | |
| 2792 | + $sstValue = $this->sst[$index]['value']; | |
| 2793 | + $fmtRuns = $this->sst[$index]['fmtRuns']; | |
| 2794 | + | |
| 2790 | 2795 | // add cell |
| 2791 | - if (($fmtRuns = $this->sst[$index]['fmtRuns']) && !$this->readDataOnly) { | |
| 2796 | + if ($fmtRuns && !$this->readDataOnly) { | |
| 2792 | 2797 | // then we should treat as rich text |
| 2793 | 2798 | $richText = new RichText(); |
| 2794 | 2799 | $charPos = 0; |
| 2795 | - $sstCount = count($this->sst[$index]['fmtRuns']); | |
| 2800 | + $sstCount = count($fmtRuns); | |
| 2801 | + $sstValueLength = StringHelper::countCharacters($sstValue); | |
| 2802 | + $lastFontIndex = count($this->objFonts) - 1; | |
| 2796 | 2803 | for ($i = 0; $i <= $sstCount; ++$i) { |
| 2797 | 2804 | /** @var mixed[][] $fmtRuns */ |
| 2798 | 2805 | if (isset($fmtRuns[$i])) { |
| 2799 | 2806 | /** @var int[] */ |
| @@ -2799,12 +2806,12 @@ | ||
| 2799 | 2806 | /** @var int[] */ |
| 2800 | 2807 | $temp = $fmtRuns[$i]; |
| 2801 | 2808 | $temp = $temp['charPos']; |
| 2802 | 2809 | /** @var int $charPos */ |
| 2803 | - $text = StringHelper::substring($this->sst[$index]['value'], $charPos, $temp - $charPos); | |
| 2810 | + $text = StringHelper::substring($sstValue, $charPos, $temp - $charPos); | |
| 2804 | 2811 | $charPos = $temp; |
| 2805 | 2812 | } else { |
| 2806 | - $text = StringHelper::substring($this->sst[$index]['value'], $charPos, StringHelper::countCharacters($this->sst[$index]['value'])); | |
| 2813 | + $text = StringHelper::substring($sstValue, $charPos, $sstValueLength); | |
| 2807 | 2814 | } |
| 2808 | 2815 | |
| 2809 | 2816 | if (StringHelper::countCharacters($text) > 0) { |
| 2810 | 2817 | if ($i == 0) { // first text run, no style |
| @@ -2821,10 +2828,10 @@ | ||
| 2821 | 2828 | /** @var int */ |
| 2822 | 2829 | $temp = $fmtRuns[$i - 1]['fontIndex']; |
| 2823 | 2830 | $fontIndex = $temp - 1; |
| 2824 | 2831 | } |
| 2825 | - if (array_key_exists($fontIndex, $this->objFonts) === false) { | |
| 2826 | - $fontIndex = count($this->objFonts) - 1; | |
| 2832 | + if ($fontIndex > $lastFontIndex) { | |
| 2833 | + $fontIndex = $lastFontIndex; | |
| 2827 | 2834 | } |
| 2828 | 2835 | $textRun->setFont(clone $this->objFonts[$fontIndex]); |
| 2829 | 2836 | } |
| 2830 | 2837 | } |
| @@ -2830,22 +2837,23 @@ | ||
| 2830 | 2837 | } |
| 2831 | 2838 | } |
| 2832 | 2839 | } |
| 2833 | 2840 | if ($this->readEmptyCells || trim($richText->getPlainText()) !== '') { |
| 2834 | - $cell = $this->phpSheet->getCell($columnString . ($row + 1)); | |
| 2841 | + $cell = $this->phpSheet->getCell($cellCoordinate); | |
| 2842 | + if (isset($this->mapCellXfIndex[$xfIndex])) { | |
| 2843 | + $cell->setXfIndexNoUpdate($this->mapCellXfIndex[$xfIndex]); | |
| 2844 | + } | |
| 2835 | 2845 | $cell->setValueExplicit($richText, DataType::TYPE_STRING); |
| 2836 | 2846 | } |
| 2837 | 2847 | } else { |
| 2838 | - if ($this->readEmptyCells || trim($this->sst[$index]['value']) !== '') { | |
| 2839 | - $cell = $this->phpSheet->getCell($columnString . ($row + 1)); | |
| 2840 | - $cell->setValueExplicit($this->sst[$index]['value'], DataType::TYPE_STRING); | |
| 2848 | + if ($this->readEmptyCells || trim($sstValue) !== '') { | |
| 2849 | + $cell = $this->phpSheet->getCell($cellCoordinate); | |
| 2850 | + if (!$this->readDataOnly && isset($this->mapCellXfIndex[$xfIndex])) { | |
| 2851 | + $cell->setXfIndexNoUpdate($this->mapCellXfIndex[$xfIndex]); | |
| 2852 | + } | |
| 2853 | + $cell->setValueExplicit($sstValue, DataType::TYPE_STRING); | |
| 2841 | 2854 | } |
| 2842 | 2855 | } |
| 2843 | - | |
| 2844 | - if (!$this->readDataOnly && $cell !== null && isset($this->mapCellXfIndex[$xfIndex])) { | |
| 2845 | - // add style information | |
| 2846 | - $cell->setXfIndex($this->mapCellXfIndex[$xfIndex]); | |
| 2847 | - } | |
| 2848 | 2856 | } |
| 2849 | 2857 | } |
| 2850 | 2858 | |
| 2851 | 2859 | /** |
| @@ -2876,22 +2884,23 @@ | ||
| 2876 | 2884 | |
| 2877 | 2885 | // offset within record data |
| 2878 | 2886 | $offset = 4; |
| 2879 | 2887 | |
| 2888 | + $rowIndex = $row + 1; | |
| 2880 | 2889 | for ($i = 1; $i <= $columns; ++$i) { |
| 2881 | 2890 | $columnString = Coordinate::stringFromColumnIndex($colFirst + $i); |
| 2882 | 2891 | |
| 2883 | 2892 | // Read cell? |
| 2884 | - if ($this->readFilter->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) { | |
| 2893 | + if ($this->readFilter->readCell($columnString, $rowIndex, $this->phpSheetTitle)) { | |
| 2885 | 2894 | // offset: var; size: 2; index to XF record |
| 2886 | 2895 | $xfIndex = self::getUInt2d($recordData, $offset); |
| 2887 | 2896 | |
| 2888 | 2897 | // offset: var; size: 4; RK value |
| 2889 | 2898 | $numValue = self::getIEEE754(self::getInt4d($recordData, $offset + 2)); |
| 2890 | - $cell = $this->phpSheet->getCell($columnString . ($row + 1)); | |
| 2899 | + $cell = $this->phpSheet->getCell($columnString . $rowIndex); | |
| 2891 | 2900 | if (!$this->readDataOnly && isset($this->mapCellXfIndex[$xfIndex])) { |
| 2892 | 2901 | // add style |
| 2893 | - $cell->setXfIndex($this->mapCellXfIndex[$xfIndex]); | |
| 2902 | + $cell->setXfIndexNoUpdate($this->mapCellXfIndex[$xfIndex]); | |
| 2894 | 2903 | } |
| 2895 | 2904 | |
| 2896 | 2905 | // add cell value |
| 2897 | 2906 | $cell->setValueExplicit($numValue, DataType::TYPE_NUMERIC); |
| @@ -2922,20 +2931,21 @@ | ||
| 2922 | 2931 | |
| 2923 | 2932 | // offset: 2; size 2; index to column |
| 2924 | 2933 | $column = self::getUInt2d($recordData, 2); |
| 2925 | 2934 | $columnString = Coordinate::stringFromColumnIndex($column + 1); |
| 2935 | + $cellCoordinate = $columnString . ($row + 1); | |
| 2926 | 2936 | |
| 2927 | 2937 | // Read cell? |
| 2928 | - if ($this->readFilter->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) { | |
| 2938 | + if ($this->readFilter->readCell($columnString, $row + 1, $this->phpSheetTitle)) { | |
| 2929 | 2939 | // offset 4; size: 2; index to XF record |
| 2930 | 2940 | $xfIndex = self::getUInt2d($recordData, 4); |
| 2931 | 2941 | |
| 2932 | 2942 | $numValue = self::extractNumber((string) substr($recordData, 6, 8)); |
| 2933 | 2943 | |
| 2934 | - $cell = $this->phpSheet->getCell($columnString . ($row + 1)); | |
| 2944 | + $cell = $this->phpSheet->getCell($cellCoordinate); | |
| 2935 | 2945 | if (!$this->readDataOnly && isset($this->mapCellXfIndex[$xfIndex])) { |
| 2936 | 2946 | // add cell style |
| 2937 | - $cell->setXfIndex($this->mapCellXfIndex[$xfIndex]); | |
| 2947 | + $cell->setXfIndexNoUpdate($this->mapCellXfIndex[$xfIndex]); | |
| 2938 | 2948 | } |
| 2939 | 2949 | |
| 2940 | 2950 | // add cell value |
| 2941 | 2951 | $cell->setValueExplicit($numValue, DataType::TYPE_NUMERIC); |
| @@ -2963,8 +2973,9 @@ | ||
| 2963 | 2973 | |
| 2964 | 2974 | // offset: 2; size: 2; col index |
| 2965 | 2975 | $column = self::getUInt2d($recordData, 2); |
| 2966 | 2976 | $columnString = Coordinate::stringFromColumnIndex($column + 1); |
| 2977 | + $cellCoordinate = $columnString . ($row + 1); | |
| 2967 | 2978 | |
| 2968 | 2979 | // offset: 20: size: variable; formula structure |
| 2969 | 2980 | $formulaStructure = (string) substr($recordData, 20); |
| 2970 | 2981 | |
| @@ -2990,12 +3001,12 @@ | ||
| 2990 | 3001 | $this->baseCell = Coordinate::stringFromColumnIndex($baseCol + 1) . ($baseRow + 1); |
| 2991 | 3002 | } |
| 2992 | 3003 | |
| 2993 | 3004 | // Read cell? |
| 2994 | - if ($this->readFilter->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) { | |
| 3005 | + if ($this->readFilter->readCell($columnString, $row + 1, $this->phpSheetTitle)) { | |
| 2995 | 3006 | if ($isPartOfSharedFormula) { |
| 2996 | 3007 | // formula is added to this cell after the sheet has been read |
| 2997 | - $this->sharedFormulaParts[$columnString . ($row + 1)] = $this->baseCell; | |
| 3008 | + $this->sharedFormulaParts[$cellCoordinate] = $this->baseCell; | |
| 2998 | 3009 | } |
| 2999 | 3010 | |
| 3000 | 3011 | // offset: 16: size: 4; not used |
| 3001 | 3012 | |
| @@ -3002,9 +3013,11 @@ | ||
| 3002 | 3013 | // offset: 4; size: 2; XF index |
| 3003 | 3014 | $xfIndex = self::getUInt2d($recordData, 4); |
| 3004 | 3015 | |
| 3005 | 3016 | // offset: 6; size: 8; result of the formula |
| 3006 | - if ((ord($recordData[6]) == 0) && (ord($recordData[12]) == 255) && (ord($recordData[13]) == 255)) { | |
| 3017 | + $resultType = ord($recordData[6]); | |
| 3018 | + $isSpecialResult = (ord($recordData[12]) == 255) && (ord($recordData[13]) == 255); | |
| 3019 | + if (($resultType == 0) && $isSpecialResult) { | |
| 3007 | 3020 | // String formula. Result follows in appended STRING record |
| 3008 | 3021 | $dataType = DataType::TYPE_STRING; |
| 3009 | 3022 | |
| 3010 | 3023 | // read possible SHAREDFMLA record |
| @@ -3014,29 +3027,17 @@ | ||
| 3014 | 3027 | } |
| 3015 | 3028 | |
| 3016 | 3029 | // read STRING record |
| 3017 | 3030 | $value = $this->readString(); |
| 3018 | - } elseif ( | |
| 3019 | - (ord($recordData[6]) == 1) | |
| 3020 | - && (ord($recordData[12]) == 255) | |
| 3021 | - && (ord($recordData[13]) == 255) | |
| 3022 | - ) { | |
| 3031 | + } elseif (($resultType == 1) && $isSpecialResult) { | |
| 3023 | 3032 | // Boolean formula. Result is in +2; 0=false, 1=true |
| 3024 | 3033 | $dataType = DataType::TYPE_BOOL; |
| 3025 | 3034 | $value = (bool) ord($recordData[8]); |
| 3026 | - } elseif ( | |
| 3027 | - (ord($recordData[6]) == 2) | |
| 3028 | - && (ord($recordData[12]) == 255) | |
| 3029 | - && (ord($recordData[13]) == 255) | |
| 3030 | - ) { | |
| 3035 | + } elseif (($resultType == 2) && $isSpecialResult) { | |
| 3031 | 3036 | // Error formula. Error code is in +2 |
| 3032 | 3037 | $dataType = DataType::TYPE_ERROR; |
| 3033 | 3038 | $value = Xls\ErrorCode::lookup(ord($recordData[8])); |
| 3034 | - } elseif ( | |
| 3035 | - (ord($recordData[6]) == 3) | |
| 3036 | - && (ord($recordData[12]) == 255) | |
| 3037 | - && (ord($recordData[13]) == 255) | |
| 3038 | - ) { | |
| 3039 | + } elseif (($resultType == 3) && $isSpecialResult) { | |
| 3039 | 3040 | // Formula result is a null string |
| 3040 | 3041 | $dataType = DataType::TYPE_NULL; |
| 3041 | 3042 | $value = ''; |
| 3042 | 3043 | } else { |
| @@ -3044,12 +3045,14 @@ | ||
| 3044 | 3045 | $dataType = DataType::TYPE_NUMERIC; |
| 3045 | 3046 | $value = self::extractNumber((string) substr($recordData, 6, 8)); |
| 3046 | 3047 | } |
| 3047 | 3048 | |
| 3048 | - $cell = $this->phpSheet->getCell($columnString . ($row + 1)); | |
| 3049 | + $cell = $this->phpSheet->getCell($cellCoordinate); | |
| 3049 | 3050 | if (!$this->readDataOnly && isset($this->mapCellXfIndex[$xfIndex])) { |
| 3050 | - // add cell style | |
| 3051 | - $cell->setXfIndex($this->mapCellXfIndex[$xfIndex]); | |
| 3051 | + // add cell style; skipping the collection update is safe here | |
| 3052 | + // because every path below ends in setCalculatedValue(), which | |
| 3053 | + // performs the update | |
| 3054 | + $cell->setXfIndexNoUpdate($this->mapCellXfIndex[$xfIndex]); | |
| 3052 | 3055 | } |
| 3053 | 3056 | |
| 3054 | 3057 | // store the formula |
| 3055 | 3058 | if (!$isPartOfSharedFormula) { |
| @@ -3154,11 +3157,12 @@ | ||
| 3154 | 3157 | |
| 3155 | 3158 | // offset: 2; size: 2; column index |
| 3156 | 3159 | $column = self::getUInt2d($recordData, 2); |
| 3157 | 3160 | $columnString = Coordinate::stringFromColumnIndex($column + 1); |
| 3161 | + $cellCoordinate = $columnString . ($row + 1); | |
| 3158 | 3162 | |
| 3159 | 3163 | // Read cell? |
| 3160 | - if ($this->readFilter->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) { | |
| 3164 | + if ($this->readFilter->readCell($columnString, $row + 1, $this->phpSheetTitle)) { | |
| 3161 | 3165 | // offset: 4; size: 2; index to XF record |
| 3162 | 3166 | $xfIndex = self::getUInt2d($recordData, 4); |
| 3163 | 3167 | |
| 3164 | 3168 | // offset: 6; size: 1; the boolean value or error value |
| @@ -3166,9 +3170,14 @@ | ||
| 3166 | 3170 | |
| 3167 | 3171 | // offset: 7; size: 1; 0=boolean; 1=error |
| 3168 | 3172 | $isError = ord($recordData[7]); |
| 3169 | 3173 | |
| 3170 | - $cell = $this->phpSheet->getCell($columnString . ($row + 1)); | |
| 3174 | + $cell = $this->phpSheet->getCell($cellCoordinate); | |
| 3175 | + if (!$this->readDataOnly && isset($this->mapCellXfIndex[$xfIndex])) { | |
| 3176 | + // add cell style; a value write does not follow on every path, | |
| 3177 | + // so use the updating setter to guarantee persistence | |
| 3178 | + $cell->setXfIndex($this->mapCellXfIndex[$xfIndex]); | |
| 3179 | + } | |
| 3171 | 3180 | switch ($isError) { |
| 3172 | 3181 | case 0: // boolean |
| 3173 | 3182 | $value = (bool) $boolErr; |
| 3174 | 3183 | |
| @@ -3183,13 +3192,8 @@ | ||
| 3183 | 3192 | $cell->setValueExplicit($value, DataType::TYPE_ERROR); |
| 3184 | 3193 | |
| 3185 | 3194 | break; |
| 3186 | 3195 | } |
| 3187 | - | |
| 3188 | - if (!$this->readDataOnly && isset($this->mapCellXfIndex[$xfIndex])) { | |
| 3189 | - // add cell style | |
| 3190 | - $cell->setXfIndex($this->mapCellXfIndex[$xfIndex]); | |
| 3191 | - } | |
| 3192 | 3196 | } |
| 3193 | 3197 | } |
| 3194 | 3198 | |
| 3195 | 3199 | /** |
| @@ -3216,16 +3220,19 @@ | ||
| 3216 | 3220 | |
| 3217 | 3221 | // offset: 4; size: 2 x nc; list of indexes to XF records |
| 3218 | 3222 | // add style information |
| 3219 | 3223 | if (!$this->readDataOnly && $this->readEmptyCells) { |
| 3224 | + $rowIndex = $row + 1; | |
| 3220 | 3225 | for ($i = 0; $i < $length / 2 - 3; ++$i) { |
| 3221 | 3226 | $columnString = Coordinate::stringFromColumnIndex($fc + $i + 1); |
| 3222 | 3227 | |
| 3223 | 3228 | // Read cell? |
| 3224 | - if ($this->readFilter->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) { | |
| 3229 | + if ($this->readFilter->readCell($columnString, $rowIndex, $this->phpSheetTitle)) { | |
| 3225 | 3230 | $xfIndex = self::getUInt2d($recordData, 4 + 2 * $i); |
| 3226 | 3231 | if (isset($this->mapCellXfIndex[$xfIndex])) { |
| 3227 | - $this->phpSheet->getCell($columnString . ($row + 1))->setXfIndex($this->mapCellXfIndex[$xfIndex]); | |
| 3232 | + // blank cells never receive a value write, so use the | |
| 3233 | + // updating setter to guarantee persistence | |
| 3234 | + $this->phpSheet->getCell($columnString . $rowIndex)->setXfIndex($this->mapCellXfIndex[$xfIndex]); | |
| 3228 | 3235 | } |
| 3229 | 3236 | } |
| 3230 | 3237 | } |
| 3231 | 3238 | } |
| @@ -3256,11 +3263,12 @@ | ||
| 3256 | 3263 | |
| 3257 | 3264 | // offset: 2; size: 2; index to column |
| 3258 | 3265 | $column = self::getUInt2d($recordData, 2); |
| 3259 | 3266 | $columnString = Coordinate::stringFromColumnIndex($column + 1); |
| 3267 | + $cellCoordinate = $columnString . ($row + 1); | |
| 3260 | 3268 | |
| 3261 | 3269 | // Read cell? |
| 3262 | - if ($this->readFilter->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) { | |
| 3270 | + if ($this->readFilter->readCell($columnString, $row + 1, $this->phpSheetTitle)) { | |
| 3263 | 3271 | // offset: 4; size: 2; XF index |
| 3264 | 3272 | $xfIndex = self::getUInt2d($recordData, 4); |
| 3265 | 3273 | |
| 3266 | 3274 | // add cell value |
| @@ -3273,15 +3281,14 @@ | ||
| 3273 | 3281 | $value = $string['value']; |
| 3274 | 3282 | } |
| 3275 | 3283 | /** @var string $value */ |
| 3276 | 3284 | if ($this->readEmptyCells || trim($value) !== '') { |
| 3277 | - $cell = $this->phpSheet->getCell($columnString . ($row + 1)); | |
| 3278 | - $cell->setValueExplicit($value, DataType::TYPE_STRING); | |
| 3279 | - | |
| 3285 | + $cell = $this->phpSheet->getCell($cellCoordinate); | |
| 3280 | 3286 | if (!$this->readDataOnly && isset($this->mapCellXfIndex[$xfIndex])) { |
| 3281 | 3287 | // add cell style |
| 3282 | - $cell->setXfIndex($this->mapCellXfIndex[$xfIndex]); | |
| 3288 | + $cell->setXfIndexNoUpdate($this->mapCellXfIndex[$xfIndex]); | |
| 3283 | 3289 | } |
| 3290 | + $cell->setValueExplicit($value, DataType::TYPE_STRING); | |
| 3284 | 3291 | } |
| 3285 | 3292 | } |
| 3286 | 3293 | } |
| 3287 | 3294 | |
| @@ -3302,16 +3309,19 @@ | ||
| 3302 | 3309 | // offset: 2; size: 2; col index |
| 3303 | 3310 | $col = self::getUInt2d($recordData, 2); |
| 3304 | 3311 | $columnString = Coordinate::stringFromColumnIndex($col + 1); |
| 3305 | 3312 | |
| 3313 | + $rowIndex = $row + 1; | |
| 3314 | + | |
| 3306 | 3315 | // Read cell? |
| 3307 | - if ($this->readFilter->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) { | |
| 3316 | + if ($this->readFilter->readCell($columnString, $rowIndex, $this->phpSheetTitle)) { | |
| 3308 | 3317 | // offset: 4; size: 2; XF index |
| 3309 | 3318 | $xfIndex = self::getUInt2d($recordData, 4); |
| 3310 | 3319 | |
| 3311 | - // add style information | |
| 3320 | + // add style information; blank cells never receive a value write, | |
| 3321 | + // so use the updating setter to guarantee persistence | |
| 3312 | 3322 | if (!$this->readDataOnly && $this->readEmptyCells && isset($this->mapCellXfIndex[$xfIndex])) { |
| 3313 | - $this->phpSheet->getCell($columnString . ($row + 1))->setXfIndex($this->mapCellXfIndex[$xfIndex]); | |
| 3323 | + $this->phpSheet->getCell($columnString . $rowIndex)->setXfIndex($this->mapCellXfIndex[$xfIndex]); | |
| 3314 | 3324 | } |
| 3315 | 3325 | } |
| 3316 | 3326 | } |
| 3317 | 3327 | |
| @@ -3611,9 +3621,9 @@ | ||
| 3611 | 3621 | $rangeBoundaries = Coordinate::getRangeBoundaries($cellRangeAddress); |
| 3612 | 3622 | StringHelper::stringIncrement($rangeBoundaries[1][0]); |
| 3613 | 3623 | for ($row = $rangeBoundaries[0][1]; $row <= $rangeBoundaries[1][1]; ++$row) { |
| 3614 | 3624 | for ($column = $rangeBoundaries[0][0]; $column != $rangeBoundaries[1][0]; StringHelper::stringIncrement($column)) { |
| 3615 | - if ($this->readFilter->readCell($column, $row, $this->phpSheet->getTitle())) { | |
| 3625 | + if ($this->readFilter->readCell($column, $row, $this->phpSheetTitle)) { | |
| 3616 | 3626 | $includeCellRange = true; |
| 3617 | 3627 | |
| 3618 | 3628 | break 2; |
| 3619 | 3629 | } |