31
31
use PhpOffice \PhpSpreadsheet \Shared \StringHelper ;
32
32
use PhpOffice \PhpSpreadsheet \Spreadsheet ;
33
33
use PhpOffice \PhpSpreadsheet \Style \Color ;
34
+ use PhpOffice \PhpSpreadsheet \Style \Font as StyleFont ;
34
35
use PhpOffice \PhpSpreadsheet \Style \NumberFormat ;
35
36
use PhpOffice \PhpSpreadsheet \Style \Style ;
36
37
use PhpOffice \PhpSpreadsheet \Worksheet \HeaderFooterDrawing ;
@@ -293,7 +294,7 @@ public function listWorksheetInfo($filename)
293
294
return $ worksheetInfo ;
294
295
}
295
296
296
- private static function castToBoolean ($ c )
297
+ private static function castToBoolean (SimpleXMLElement $ c ): bool
297
298
{
298
299
$ value = isset ($ c ->v ) ? (string ) $ c ->v : null ;
299
300
if ($ value == '0 ' ) {
@@ -305,17 +306,21 @@ private static function castToBoolean($c)
305
306
return (bool ) $ c ->v ;
306
307
}
307
308
308
- private static function castToError ($ c )
309
+ private static function castToError (SimpleXMLElement $ c ): ? string
309
310
{
310
311
return isset ($ c ->v ) ? (string ) $ c ->v : null ;
311
312
}
312
313
313
- private static function castToString ($ c )
314
+ private static function castToString (SimpleXMLElement $ c ): ? string
314
315
{
315
316
return isset ($ c ->v ) ? (string ) $ c ->v : null ;
316
317
}
317
318
318
- private function castToFormula ($ c , $ r , &$ cellDataType , &$ value , &$ calculatedValue , &$ sharedFormulas , $ castBaseType ): void
319
+ /**
320
+ * @param mixed $value
321
+ * @param mixed $calculatedValue
322
+ */
323
+ private function castToFormula (SimpleXMLElement $ c , string $ r , string &$ cellDataType , &$ value , &$ calculatedValue , array &$ sharedFormulas , string $ castBaseType ): void
319
324
{
320
325
$ attr = $ c ->f ->attributes ();
321
326
$ cellDataType = 'f ' ;
@@ -389,7 +394,7 @@ private function getFromZipArchive(ZipArchive $archive, $fileName = '')
389
394
$ contents = $ archive ->getFromName (substr ($ fileName , 1 ), 0 , ZipArchive::FL_NOCASE );
390
395
}
391
396
392
- return $ contents ;
397
+ return ( $ contents === false ) ? '' : $ contents ;
393
398
}
394
399
395
400
/**
@@ -1143,7 +1148,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
1143
1148
}
1144
1149
1145
1150
// Header/footer images
1146
- if ($ xmlSheet && $ xmlSheet ->legacyDrawingHF && ! $ this -> readDataOnly ) {
1151
+ if ($ xmlSheet && $ xmlSheet ->legacyDrawingHF ) {
1147
1152
if ($ zip ->locateName (dirname ("$ dir/ $ fileWorksheet " ) . '/_rels/ ' . basename ($ fileWorksheet ) . '.rels ' )) {
1148
1153
$ relsWorksheet = $ this ->loadZipNoNamespace (dirname ("$ dir/ $ fileWorksheet " ) . '/_rels/ ' . basename ($ fileWorksheet ) . '.rels ' , Namespaces::RELATIONSHIPS );
1149
1154
$ vmlRelationship = '' ;
@@ -1550,7 +1555,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
1550
1555
1551
1556
break ;
1552
1557
case '_xlnm.Print_Area ' :
1553
- $ rangeSets = preg_split ("/('?(?:.*?)'?(?:![A-Z0-9]+:[A-Z0-9]+)),?/ " , $ extractedRange , -1 , PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE );
1558
+ $ rangeSets = preg_split ("/('?(?:.*?)'?(?:![A-Z0-9]+:[A-Z0-9]+)),?/ " , $ extractedRange , -1 , PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE ) ?: [] ;
1554
1559
$ newRangeSets = [];
1555
1560
foreach ($ rangeSets as $ rangeSet ) {
1556
1561
[, $ rangeSet ] = Worksheet::extractSheetTitle ($ rangeSet , true );
@@ -1605,7 +1610,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
1605
1610
if (strpos ((string ) $ definedName , '! ' ) !== false ) {
1606
1611
$ range [0 ] = str_replace ("'' " , "' " , $ range [0 ]);
1607
1612
$ range [0 ] = str_replace ("' " , '' , $ range [0 ]);
1608
- if ($ worksheet = $ excel ->getSheetByName ($ range [0 ])) {
1613
+ if ($ worksheet = $ excel ->getSheetByName ($ range [0 ])) { // @phpstan-ignore-line
1609
1614
$ excel ->addDefinedName (DefinedName::createInstance ((string ) $ definedName ['name ' ], $ worksheet , $ extractedRange , true , $ scope ));
1610
1615
} else {
1611
1616
$ excel ->addDefinedName (DefinedName::createInstance ((string ) $ definedName ['name ' ], $ scope , $ extractedRange , true , $ scope ));
@@ -1626,7 +1631,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
1626
1631
// Need to split on a comma or a space if not in quotes, and extract the first part.
1627
1632
$ definedNameValueParts = preg_split ("/[ ,](?=([^']*'[^']*')*[^']*$)/miuU " , $ definedRange );
1628
1633
// Extract sheet name
1629
- [$ extractedSheetName ] = Worksheet::extractSheetTitle ((string ) $ definedNameValueParts [0 ], true );
1634
+ [$ extractedSheetName ] = Worksheet::extractSheetTitle ((string ) $ definedNameValueParts [0 ], true ); // @phpstan-ignore-line
1630
1635
$ extractedSheetName = trim ($ extractedSheetName , "' " );
1631
1636
1632
1637
// Locate sheet
@@ -1673,7 +1678,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
1673
1678
if (isset ($ charts [$ chartEntryRef ])) {
1674
1679
$ chartPositionRef = $ charts [$ chartEntryRef ]['sheet ' ] . '! ' . $ charts [$ chartEntryRef ]['id ' ];
1675
1680
if (isset ($ chartDetails [$ chartPositionRef ])) {
1676
- $ excel ->getSheetByName ($ charts [$ chartEntryRef ]['sheet ' ])->addChart ($ objChart );
1681
+ $ excel ->getSheetByName ($ charts [$ chartEntryRef ]['sheet ' ])->addChart ($ objChart ); // @phpstan-ignore-line
1677
1682
$ objChart ->setWorksheet ($ excel ->getSheetByName ($ charts [$ chartEntryRef ]['sheet ' ]));
1678
1683
// For oneCellAnchor or absoluteAnchor positioned charts,
1679
1684
// toCoordinate is not in the data. Does it need to be calculated?
@@ -1721,36 +1726,37 @@ private function parseRichText(?SimpleXMLElement $is)
1721
1726
if (isset ($ is ->t )) {
1722
1727
$ value ->createText (StringHelper::controlCharacterOOXML2PHP ((string ) $ is ->t ));
1723
1728
} else {
1724
- if (is_object ($ is ->r )) {
1729
+ if (isset ( $ is -> r ) && is_object ($ is ->r )) {
1725
1730
/** @var SimpleXMLElement $run */
1726
1731
foreach ($ is ->r as $ run ) {
1727
1732
if (!isset ($ run ->rPr )) {
1728
1733
$ value ->createText (StringHelper::controlCharacterOOXML2PHP ((string ) $ run ->t ));
1729
1734
} else {
1730
1735
$ objText = $ value ->createTextRun (StringHelper::controlCharacterOOXML2PHP ((string ) $ run ->t ));
1736
+ $ objFont = $ objText ->getFont () ?? new StyleFont ();
1731
1737
1732
1738
if (isset ($ run ->rPr ->rFont )) {
1733
1739
$ attr = $ run ->rPr ->rFont ->attributes ();
1734
1740
if (isset ($ attr ['val ' ])) {
1735
- $ objText -> getFont () ->setName ((string ) $ attr ['val ' ]);
1741
+ $ objFont ->setName ((string ) $ attr ['val ' ]);
1736
1742
}
1737
1743
}
1738
1744
if (isset ($ run ->rPr ->sz )) {
1739
1745
$ attr = $ run ->rPr ->sz ->attributes ();
1740
1746
if (isset ($ attr ['val ' ])) {
1741
- $ objText -> getFont () ->setSize ((float ) $ attr ['val ' ]);
1747
+ $ objFont ->setSize ((float ) $ attr ['val ' ]);
1742
1748
}
1743
1749
}
1744
1750
if (isset ($ run ->rPr ->color )) {
1745
- $ objText -> getFont () ->setColor (new Color ($ this ->styleReader ->readColor ($ run ->rPr ->color )));
1751
+ $ objFont ->setColor (new Color ($ this ->styleReader ->readColor ($ run ->rPr ->color )));
1746
1752
}
1747
1753
if (isset ($ run ->rPr ->b )) {
1748
1754
$ attr = $ run ->rPr ->b ->attributes ();
1749
1755
if (
1750
1756
(isset ($ attr ['val ' ]) && self ::boolean ((string ) $ attr ['val ' ])) ||
1751
1757
(!isset ($ attr ['val ' ]))
1752
1758
) {
1753
- $ objText -> getFont () ->setBold (true );
1759
+ $ objFont ->setBold (true );
1754
1760
}
1755
1761
}
1756
1762
if (isset ($ run ->rPr ->i )) {
@@ -1759,27 +1765,27 @@ private function parseRichText(?SimpleXMLElement $is)
1759
1765
(isset ($ attr ['val ' ]) && self ::boolean ((string ) $ attr ['val ' ])) ||
1760
1766
(!isset ($ attr ['val ' ]))
1761
1767
) {
1762
- $ objText -> getFont () ->setItalic (true );
1768
+ $ objFont ->setItalic (true );
1763
1769
}
1764
1770
}
1765
1771
if (isset ($ run ->rPr ->vertAlign )) {
1766
1772
$ attr = $ run ->rPr ->vertAlign ->attributes ();
1767
1773
if (isset ($ attr ['val ' ])) {
1768
1774
$ vertAlign = strtolower ((string ) $ attr ['val ' ]);
1769
1775
if ($ vertAlign == 'superscript ' ) {
1770
- $ objText -> getFont () ->setSuperscript (true );
1776
+ $ objFont ->setSuperscript (true );
1771
1777
}
1772
1778
if ($ vertAlign == 'subscript ' ) {
1773
- $ objText -> getFont () ->setSubscript (true );
1779
+ $ objFont ->setSubscript (true );
1774
1780
}
1775
1781
}
1776
1782
}
1777
1783
if (isset ($ run ->rPr ->u )) {
1778
1784
$ attr = $ run ->rPr ->u ->attributes ();
1779
1785
if (!isset ($ attr ['val ' ])) {
1780
- $ objText -> getFont () ->setUnderline (\PhpOffice \PhpSpreadsheet \Style \Font::UNDERLINE_SINGLE );
1786
+ $ objFont ->setUnderline (\PhpOffice \PhpSpreadsheet \Style \Font::UNDERLINE_SINGLE );
1781
1787
} else {
1782
- $ objText -> getFont () ->setUnderline ((string ) $ attr ['val ' ]);
1788
+ $ objFont ->setUnderline ((string ) $ attr ['val ' ]);
1783
1789
}
1784
1790
}
1785
1791
if (isset ($ run ->rPr ->strike )) {
@@ -1788,7 +1794,7 @@ private function parseRichText(?SimpleXMLElement $is)
1788
1794
(isset ($ attr ['val ' ]) && self ::boolean ((string ) $ attr ['val ' ])) ||
1789
1795
(!isset ($ attr ['val ' ]))
1790
1796
) {
1791
- $ objText -> getFont () ->setStrikethrough (true );
1797
+ $ objFont ->setStrikethrough (true );
1792
1798
}
1793
1799
}
1794
1800
}
@@ -1841,17 +1847,30 @@ private function readRibbon(Spreadsheet $excel, string $customUITarget, ZipArchi
1841
1847
}
1842
1848
}
1843
1849
1850
+ /**
1851
+ * @param null|array|bool|SimpleXMLElement $array
1852
+ * @param int|string $key
1853
+ *
1854
+ * @return mixed
1855
+ */
1844
1856
private static function getArrayItem ($ array , $ key = 0 )
1845
1857
{
1846
- return $ array [$ key ] ?? null ;
1858
+ return ( $ array === null || is_bool ( $ array )) ? null : ( $ array [$ key ] ?? null ) ;
1847
1859
}
1848
1860
1861
+ /**
1862
+ * @param null|SimpleXMLElement|string $base
1863
+ * @param null|SimpleXMLElement|string $add
1864
+ */
1849
1865
private static function dirAdd ($ base , $ add ): string
1850
1866
{
1867
+ $ base = (string ) $ base ;
1868
+ $ add = (string ) $ add ;
1869
+
1851
1870
return (string ) preg_replace ('~[^/]+/\.\./~ ' , '' , dirname ($ base ) . "/ $ add " );
1852
1871
}
1853
1872
1854
- private static function toCSSArray ($ style ): array
1873
+ private static function toCSSArray (string $ style ): array
1855
1874
{
1856
1875
$ style = self ::stripWhiteSpaceFromStyleString ($ style );
1857
1876
@@ -1865,15 +1884,15 @@ private static function toCSSArray($style): array
1865
1884
}
1866
1885
if (strpos ($ item [1 ], 'pt ' ) !== false ) {
1867
1886
$ item [1 ] = str_replace ('pt ' , '' , $ item [1 ]);
1868
- $ item [1 ] = Font::fontSizeToPixels ($ item [1 ]);
1887
+ $ item [1 ] = ( string ) Font::fontSizeToPixels (( int ) $ item [1 ]);
1869
1888
}
1870
1889
if (strpos ($ item [1 ], 'in ' ) !== false ) {
1871
1890
$ item [1 ] = str_replace ('in ' , '' , $ item [1 ]);
1872
- $ item [1 ] = Font::inchSizeToPixels ($ item [1 ]);
1891
+ $ item [1 ] = ( string ) Font::inchSizeToPixels (( int ) $ item [1 ]);
1873
1892
}
1874
1893
if (strpos ($ item [1 ], 'cm ' ) !== false ) {
1875
1894
$ item [1 ] = str_replace ('cm ' , '' , $ item [1 ]);
1876
- $ item [1 ] = Font::centimeterSizeToPixels ($ item [1 ]);
1895
+ $ item [1 ] = ( string ) Font::centimeterSizeToPixels (( int ) $ item [1 ]);
1877
1896
}
1878
1897
1879
1898
$ style [$ item [0 ]] = $ item [1 ];
@@ -1882,11 +1901,14 @@ private static function toCSSArray($style): array
1882
1901
return $ style ;
1883
1902
}
1884
1903
1885
- public static function stripWhiteSpaceFromStyleString ($ string ): string
1904
+ public static function stripWhiteSpaceFromStyleString (string $ string ): string
1886
1905
{
1887
1906
return trim (str_replace (["\r" , "\n" , ' ' ], '' , $ string ), '; ' );
1888
1907
}
1889
1908
1909
+ /**
1910
+ * @param mixed $value
1911
+ */
1890
1912
private static function boolean ($ value ): bool
1891
1913
{
1892
1914
if (is_object ($ value )) {
@@ -1955,7 +1977,7 @@ private static function getLockValue(SimpleXmlElement $protection, string $key):
1955
1977
return $ returnValue ;
1956
1978
}
1957
1979
1958
- private function readFormControlProperties (Spreadsheet $ excel , $ dir , $ fileWorksheet , $ docSheet , array &$ unparsedLoadedData ): void
1980
+ private function readFormControlProperties (Spreadsheet $ excel , string $ dir , string $ fileWorksheet , Worksheet $ docSheet , array &$ unparsedLoadedData ): void
1959
1981
{
1960
1982
$ zip = $ this ->zip ;
1961
1983
if (!$ zip ->locateName (dirname ("$ dir/ $ fileWorksheet " ) . '/_rels/ ' . basename ($ fileWorksheet ) . '.rels ' )) {
@@ -1982,7 +2004,7 @@ private function readFormControlProperties(Spreadsheet $excel, $dir, $fileWorksh
1982
2004
unset($ unparsedCtrlProps );
1983
2005
}
1984
2006
1985
- private function readPrinterSettings (Spreadsheet $ excel , $ dir , $ fileWorksheet , $ docSheet , array &$ unparsedLoadedData ): void
2007
+ private function readPrinterSettings (Spreadsheet $ excel , string $ dir , string $ fileWorksheet , Worksheet $ docSheet , array &$ unparsedLoadedData ): void
1986
2008
{
1987
2009
$ zip = $ this ->zip ;
1988
2010
if (!$ zip ->locateName (dirname ("$ dir/ $ fileWorksheet " ) . '/_rels/ ' . basename ($ fileWorksheet ) . '.rels ' )) {
@@ -2070,7 +2092,7 @@ private function readAutoFilterTables(
2070
2092
if ($ xmlSheet && $ xmlSheet ->autoFilter ) {
2071
2093
// In older files, autofilter structure is defined in the worksheet file
2072
2094
(new AutoFilter ($ docSheet , $ xmlSheet ))->load ();
2073
- } elseif ($ xmlSheet && $ xmlSheet ->tableParts && $ xmlSheet ->tableParts ['count ' ] > 0 ) {
2095
+ } elseif ($ xmlSheet && $ xmlSheet ->tableParts && ( int ) $ xmlSheet ->tableParts ['count ' ] > 0 ) {
2074
2096
// But for Office365, MS decided to make it all just a bit more complicated
2075
2097
$ this ->readAutoFilterTablesInTablesFile ($ xmlSheet , $ dir , $ fileWorksheet , $ zip , $ docSheet );
2076
2098
}
0 commit comments