diff --git a/composer.lock b/composer.lock index c50914164..cc01138c6 100644 --- a/composer.lock +++ b/composer.lock @@ -1798,16 +1798,16 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.11", + "version": "2.1.13", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "8ca5f79a8f63c49b2359065832a654e1ec70ac30" + "reference": "e55e03e6d4ac49cd1240907e5b08e5cd378572a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/8ca5f79a8f63c49b2359065832a654e1ec70ac30", - "reference": "8ca5f79a8f63c49b2359065832a654e1ec70ac30", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e55e03e6d4ac49cd1240907e5b08e5cd378572a9", + "reference": "e55e03e6d4ac49cd1240907e5b08e5cd378572a9", "shasum": "" }, "require": { @@ -1852,25 +1852,25 @@ "type": "github" } ], - "time": "2025-03-24T13:45:00+00:00" + "time": "2025-04-27T12:28:25+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", - "version": "2.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-deprecation-rules.git", - "reference": "1cc1259cb91ee4cfbb5c39bca9f635f067c910b4" + "reference": "9d8e7d4e32711715ad78a1fb6ec368df9af01fdf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/1cc1259cb91ee4cfbb5c39bca9f635f067c910b4", - "reference": "1cc1259cb91ee4cfbb5c39bca9f635f067c910b4", + "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/9d8e7d4e32711715ad78a1fb6ec368df9af01fdf", + "reference": "9d8e7d4e32711715ad78a1fb6ec368df9af01fdf", "shasum": "" }, "require": { "php": "^7.4 || ^8.0", - "phpstan/phpstan": "^2.0" + "phpstan/phpstan": "^2.1.13" }, "require-dev": { "php-parallel-lint/php-parallel-lint": "^1.2", @@ -1897,9 +1897,9 @@ "description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.", "support": { "issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues", - "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/2.0.1" + "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/2.0.2" }, - "time": "2024-11-28T21:56:36+00:00" + "time": "2025-04-26T19:59:57+00:00" }, { "name": "phpstan/phpstan-phpunit", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 364905f71..aab499115 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,2 +1,2 @@ parameters: - ignoreErrors: + ignoreErrors: [] diff --git a/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php b/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php index 7c2f989b8..1db0c0f5a 100644 --- a/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php +++ b/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php @@ -110,7 +110,7 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder return parent::bindValue($cell, $value); } - /** @param array{0: non-falsy-string, 1: ?string, 2: numeric-string, 3: numeric-string, 4: numeric-string} $matches */ + /** @param array{0: string, 1: ?string, 2: numeric-string, 3: numeric-string, 4: numeric-string} $matches */ protected function setImproperFraction(array $matches, Cell $cell): bool { // Convert value to number @@ -131,7 +131,7 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder return true; } - /** @param array{0: non-falsy-string, 1: ?string, 2: numeric-string, 3: numeric-string} $matches */ + /** @param array{0: string, 1: ?string, 2: numeric-string, 3: numeric-string} $matches */ protected function setProperFraction(array $matches, Cell $cell): bool { // Convert value to number diff --git a/src/PhpSpreadsheet/Cell/Cell.php b/src/PhpSpreadsheet/Cell/Cell.php index 704352456..08175fc1e 100644 --- a/src/PhpSpreadsheet/Cell/Cell.php +++ b/src/PhpSpreadsheet/Cell/Cell.php @@ -497,10 +497,9 @@ class Cell implements Stringable if (isset($matches[3])) { $minCol = $matches[1]; $minRow = (int) $matches[2]; - // https://github.com/phpstan/phpstan/issues/11602 - $maxCol = $matches[4]; // @phpstan-ignore-line + $maxCol = $matches[4]; ++$maxCol; - $maxRow = (int) $matches[5]; // @phpstan-ignore-line + $maxRow = (int) $matches[5]; for ($row = $minRow; $row <= $maxRow; ++$row) { for ($col = $minCol; $col !== $maxCol; ++$col) { if ("$col$row" !== $coordinate) { diff --git a/src/PhpSpreadsheet/Chart/ChartColor.php b/src/PhpSpreadsheet/Chart/ChartColor.php index d6306de6b..6ac4b5acf 100644 --- a/src/PhpSpreadsheet/Chart/ChartColor.php +++ b/src/PhpSpreadsheet/Chart/ChartColor.php @@ -22,7 +22,7 @@ class ChartColor private ?int $brightness = null; /** - * @param string|string[] $value + * @param array{value: ?string, alpha: null|int|string, brightness?: null|int|string, type: ?string}|string $value */ public function __construct($value = '', ?int $alpha = null, ?string $type = null, ?int $brightness = null) { @@ -114,6 +114,7 @@ class ChartColor return $this; } + /** @param array{value: ?string, alpha: null|int|string, brightness?: null|int|string, type: ?string} $color */ public function setColorPropertiesArray(array $color): self { return $this->setColorProperties( diff --git a/src/PhpSpreadsheet/Chart/Properties.php b/src/PhpSpreadsheet/Chart/Properties.php index 3e02a964f..64f97d53c 100644 --- a/src/PhpSpreadsheet/Chart/Properties.php +++ b/src/PhpSpreadsheet/Chart/Properties.php @@ -177,6 +177,7 @@ abstract class Properties return ((float) $value) / self::PERCENTAGE_MULTIPLIER; } + /** @return array{type: ?string, value: ?string, alpha: ?int} */ protected function setColorProperties(?string $color, null|float|int|string $alpha, ?string $colorType): array { return [ @@ -506,11 +507,14 @@ abstract class Properties return $this->softEdges['size']; } + /** @param null|array{value?: ?string, alpha?: null|int|string, brightness?: null|int|string, type?: ?string}|float|string $value */ public function setShadowProperty(string $propertyName, mixed $value): self { $this->activateObject(); if ($propertyName === 'color' && is_array($value)) { - $this->shadowColor->setColorPropertiesArray($value); + /** @var array{value: ?string, alpha: null|int|string, brightness?: null|int|string, type: ?string} */ + $valuex = $value; + $this->shadowColor->setColorPropertiesArray($valuex); } else { $this->shadowProperties[$propertyName] = $value; } diff --git a/src/PhpSpreadsheet/Helper/Html.php b/src/PhpSpreadsheet/Helper/Html.php index 46fdd7547..b668206e3 100644 --- a/src/PhpSpreadsheet/Helper/Html.php +++ b/src/PhpSpreadsheet/Helper/Html.php @@ -557,6 +557,7 @@ class Html /** @var callable[] */ protected array $endTagCallbacks; + /** @var mixed[] */ private array $stack = []; public string $stringData = ''; @@ -711,7 +712,10 @@ class Html public static function colourNameLookup(string $colorName): string { - return static::COLOUR_MAP[$colorName] ?? ''; + /** @var string[] */ + $temp = static::COLOUR_MAP; + + return $temp[$colorName] ?? ''; } protected function startFontTag(DOMElement $tag): void diff --git a/src/PhpSpreadsheet/Helper/Sample.php b/src/PhpSpreadsheet/Helper/Sample.php index 7176696dd..729d5d736 100644 --- a/src/PhpSpreadsheet/Helper/Sample.php +++ b/src/PhpSpreadsheet/Helper/Sample.php @@ -241,6 +241,7 @@ class Sample : $this->log(sprintf('Function: %s() - %s.', rtrim($functionName, '()'), rtrim($description, '.'))); } + /** @param mixed[][] $matrix */ public function displayGrid(array $matrix): void { $renderer = new TextGrid($matrix, $this->isCli()); diff --git a/src/PhpSpreadsheet/Helper/TextGrid.php b/src/PhpSpreadsheet/Helper/TextGrid.php index c7868c050..9c64c617c 100644 --- a/src/PhpSpreadsheet/Helper/TextGrid.php +++ b/src/PhpSpreadsheet/Helper/TextGrid.php @@ -8,10 +8,13 @@ class TextGrid { private bool $isCli; + /** @var mixed[][] */ protected array $matrix; + /** @var int[] */ protected array $rows; + /** @var string[] */ protected array $columns; private string $gridDisplay; @@ -22,6 +25,7 @@ class TextGrid private bool $columnHeaders = true; + /** @param mixed[][] $matrix */ public function __construct(array $matrix, bool $isCli = true, bool $rowDividers = false, bool $rowHeaders = true, bool $columnHeaders = true) { $this->rows = array_keys($matrix); @@ -63,6 +67,7 @@ class TextGrid return $this->gridDisplay; } + /** @param int[] $columnWidths */ private function renderRows(int $maxRowLength, array $columnWidths): void { foreach ($this->matrix as $row => $rowData) { @@ -77,6 +82,10 @@ class TextGrid } } + /** + * @param mixed[] $rowData + * @param int[] $columnWidths + */ private function renderCells(array $rowData, array $columnWidths): void { foreach ($rowData as $column => $cell) { @@ -87,6 +96,7 @@ class TextGrid } } + /** @param int[] $columnWidths */ private function renderColumnHeader(int $maxRowLength, array &$columnWidths): void { if (!$this->columnHeaders) { @@ -95,6 +105,7 @@ class TextGrid return; } foreach ($this->columns as $column => $reference) { + /** @var string $reference */ $columnWidths[$column] = max($columnWidths[$column], $this->strlen($reference)); } if ($this->rowHeaders) { @@ -109,6 +120,7 @@ class TextGrid $this->gridDisplay .= str_repeat(' ', $maxRowLength + 2); } foreach ($this->columns as $column => $reference) { + /** @var scalar $reference */ $this->gridDisplay .= '| ' . str_pad((string) $reference, $columnWidths[$column] + 1, ' '); } $this->gridDisplay .= '|' . PHP_EOL; @@ -116,6 +128,7 @@ class TextGrid $this->renderFooter($maxRowLength, $columnWidths); } + /** @param int[] $columnWidths */ private function renderFooter(int $maxRowLength, array $columnWidths): void { if ($this->rowHeaders) { @@ -128,6 +141,7 @@ class TextGrid $this->gridDisplay .= '+' . PHP_EOL; } + /** @return int[] */ private function getColumnWidths(): array { $columnCount = count($this->matrix, COUNT_RECURSIVE) / count($this->matrix); @@ -139,6 +153,7 @@ class TextGrid return $columnWidths; } + /** @param mixed[] $columnData */ private function getColumnWidth(array $columnData): int { $columnWidth = 0; diff --git a/src/PhpSpreadsheet/IOFactory.php b/src/PhpSpreadsheet/IOFactory.php index 73734fc70..e16cf62b2 100644 --- a/src/PhpSpreadsheet/IOFactory.php +++ b/src/PhpSpreadsheet/IOFactory.php @@ -116,6 +116,8 @@ abstract class IOFactory /** * Identify file type using automatic IReader resolution. + * + * @param string[] $readers */ public static function identify(string $filename, ?array $readers = null, bool $fullClassName = false): string { diff --git a/src/PhpSpreadsheet/NamedRange.php b/src/PhpSpreadsheet/NamedRange.php index 819ddeac6..c7fb853df 100644 --- a/src/PhpSpreadsheet/NamedRange.php +++ b/src/PhpSpreadsheet/NamedRange.php @@ -43,6 +43,7 @@ class NamedRange extends DefinedName return $this; } + /** @return string[] */ public function getCellsInRange(): array { $range = $this->value; diff --git a/src/PhpSpreadsheet/Reader/Csv.php b/src/PhpSpreadsheet/Reader/Csv.php index f4cdd02d3..783c4f00c 100644 --- a/src/PhpSpreadsheet/Reader/Csv.php +++ b/src/PhpSpreadsheet/Reader/Csv.php @@ -188,7 +188,8 @@ class Csv extends BaseReader */ protected function inferSeparator(): void { - if ($this->delimiter !== null) { + $temp = $this->delimiter; + if ($temp !== null) { return; } @@ -228,13 +229,15 @@ class Csv extends BaseReader $this->checkSeparator(); $this->inferSeparator(); - /** @var array */ - $worksheetInfo = []; - $worksheetInfo[0]['worksheetName'] = 'Worksheet'; - $worksheetInfo[0]['lastColumnLetter'] = 'A'; - $worksheetInfo[0]['lastColumnIndex'] = 0; - $worksheetInfo[0]['totalRows'] = 0; - $worksheetInfo[0]['totalColumns'] = 0; + $worksheetInfo = [ + [ + 'worksheetName' => 'Worksheet', + 'lastColumnLetter' => 'A', + 'lastColumnIndex' => 0, + 'totalRows' => 0, + 'totalColumns' => 0, + ], + ]; $delimiter = $this->delimiter ?? ''; // Loop through each line of the file in turn diff --git a/src/PhpSpreadsheet/Reader/Html.php b/src/PhpSpreadsheet/Reader/Html.php index 55f97d327..eb39752bf 100644 --- a/src/PhpSpreadsheet/Reader/Html.php +++ b/src/PhpSpreadsheet/Reader/Html.php @@ -51,7 +51,7 @@ class Html extends BaseReader /** * Formats. */ - protected array $formats = [ + protected const FORMATS = [ 'h1' => [ 'font' => [ 'bold' => true, @@ -128,6 +128,7 @@ class Html extends BaseReader ], // Italic ]; + /** @var array */ protected array $rowspan = []; /** @@ -218,12 +219,17 @@ class Html extends BaseReader return $this->loadIntoExisting($filename, $spreadsheet); } - // Data Array used for testing only, should write to Spreadsheet object on completion of tests - + /** + * Data Array used for testing only, should write to + * Spreadsheet object on completion of tests. + * + * @var mixed[][] + */ protected array $dataArray = []; protected int $tableLevel = 0; + /** @var string[] */ protected array $nestedColumn = ['A']; protected function setTableStartColumn(string $column): string @@ -246,12 +252,14 @@ class Html extends BaseReader { --$this->tableLevel; - return array_pop($this->nestedColumn); + return array_pop($this->nestedColumn) ?? ''; } /** * Flush cell. * + * @param string[] $attributeArray + * * @param-out string $cellContent In one case, it can be bool */ protected function flushCell(Worksheet $sheet, string $column, int|string $row, mixed &$cellContent, array $attributeArray): void @@ -345,6 +353,7 @@ class Html extends BaseReader } } + /** @param string[] $attributeArray */ private function processDomElementTitle(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void { if ($child->nodeName === 'title') { @@ -364,6 +373,7 @@ class Html extends BaseReader private const SPAN_ETC = ['span', 'div', 'font', 'i', 'em', 'strong', 'b']; + /** @param string[] $attributeArray */ private function processDomElementSpanEtc(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void { if (in_array((string) $child->nodeName, self::SPAN_ETC, true)) { @@ -376,7 +386,7 @@ class Html extends BaseReader } if (isset($attributeArray['style'])) { $alignStyle = $attributeArray['style']; - if (preg_match('/\btext-align:\s*(left|right|center|justify)\b/', $alignStyle, $matches) === 1) { + if (preg_match('/\btext-align:\s*(left|right|center|justify)\b/', (string) $alignStyle, $matches) === 1) { $sheet->getComment($column . $row)->setAlignment($matches[1]); } } @@ -384,28 +394,28 @@ class Html extends BaseReader $this->processDomElement($child, $sheet, $row, $column, $cellContent); } - if (isset($this->formats[$child->nodeName])) { - $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]); + if (isset(self::FORMATS[$child->nodeName])) { + $sheet->getStyle($column . $row)->applyFromArray(self::FORMATS[$child->nodeName]); } } else { $this->processDomElementHr($sheet, $row, $column, $cellContent, $child, $attributeArray); } } + /** @param string[] $attributeArray */ private function processDomElementHr(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void { if ($child->nodeName === 'hr') { $this->flushCell($sheet, $column, $row, $cellContent, $attributeArray); ++$row; - if (isset($this->formats[$child->nodeName])) { - $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]); - } + $sheet->getStyle($column . $row)->applyFromArray(self::FORMATS[$child->nodeName]); ++$row; } // fall through to br $this->processDomElementBr($sheet, $row, $column, $cellContent, $child, $attributeArray); } + /** @param string[] $attributeArray */ private function processDomElementBr(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void { if ($child->nodeName === 'br' || $child->nodeName === 'hr') { @@ -423,6 +433,7 @@ class Html extends BaseReader } } + /** @param string[] $attributeArray */ private function processDomElementA(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void { if ($child->nodeName === 'a') { @@ -430,9 +441,7 @@ class Html extends BaseReader switch ($attributeName) { case 'href': $sheet->getCell($column . $row)->getHyperlink()->setUrl($attributeValue); - if (isset($this->formats[$child->nodeName])) { - $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]); - } + $sheet->getStyle($column . $row)->applyFromArray(self::FORMATS[$child->nodeName]); break; case 'class': @@ -451,6 +460,7 @@ class Html extends BaseReader private const H1_ETC = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'ul', 'p']; + /** @param string[] $attributeArray */ private function processDomElementH1Etc(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void { if (in_array((string) $child->nodeName, self::H1_ETC, true)) { @@ -467,8 +477,8 @@ class Html extends BaseReader $this->processDomElement($child, $sheet, $row, $column, $cellContent); $this->flushCell($sheet, $column, $row, $cellContent, $attributeArray); - if (isset($this->formats[$child->nodeName])) { - $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]); + if (isset(self::FORMATS[$child->nodeName])) { + $sheet->getStyle($column . $row)->applyFromArray(self::FORMATS[$child->nodeName]); } ++$row; @@ -479,6 +489,7 @@ class Html extends BaseReader } } + /** @param string[] $attributeArray */ private function processDomElementLi(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void { if ($child->nodeName === 'li') { @@ -500,6 +511,7 @@ class Html extends BaseReader } } + /** @param string[] $attributeArray */ private function processDomElementImg(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void { if ($child->nodeName === 'img') { @@ -511,6 +523,7 @@ class Html extends BaseReader private string $currentColumn = 'A'; + /** @param string[] $attributeArray */ private function processDomElementTable(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void { if ($child->nodeName === 'table') { @@ -537,6 +550,7 @@ class Html extends BaseReader } } + /** @param string[] $attributeArray */ private function processDomElementTr(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void { if ($child->nodeName === 'col') { @@ -548,7 +562,7 @@ class Html extends BaseReader $this->processDomElement($child, $sheet, $row, $column, $cellContent); if (isset($attributeArray['height'])) { - $sheet->getRowDimension($row)->setRowHeight($attributeArray['height']); + $sheet->getRowDimension($row)->setRowHeight((float) $attributeArray['height']); } ++$row; @@ -557,6 +571,7 @@ class Html extends BaseReader } } + /** @param string[] $attributeArray */ private function processDomElementThTdOther(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void { if ($child->nodeName !== 'td' && $child->nodeName !== 'th') { @@ -566,6 +581,7 @@ class Html extends BaseReader } } + /** @param string[] $attributeArray */ private function processDomElementBgcolor(Worksheet $sheet, int $row, string $column, array $attributeArray): void { if (isset($attributeArray['bgcolor'])) { @@ -580,6 +596,7 @@ class Html extends BaseReader } } + /** @param string[] $attributeArray */ private function processDomElementWidth(Worksheet $sheet, string $column, array $attributeArray): void { if (isset($attributeArray['width'])) { @@ -587,6 +604,7 @@ class Html extends BaseReader } } + /** @param string[] $attributeArray */ private function processDomElementHeight(Worksheet $sheet, int $row, array $attributeArray): void { if (isset($attributeArray['height'])) { @@ -594,6 +612,7 @@ class Html extends BaseReader } } + /** @param string[] $attributeArray */ private function processDomElementAlign(Worksheet $sheet, int $row, string $column, array $attributeArray): void { if (isset($attributeArray['align'])) { @@ -601,6 +620,7 @@ class Html extends BaseReader } } + /** @param string[] $attributeArray */ private function processDomElementVAlign(Worksheet $sheet, int $row, string $column, array $attributeArray): void { if (isset($attributeArray['valign'])) { @@ -608,6 +628,7 @@ class Html extends BaseReader } } + /** @param string[] $attributeArray */ private function processDomElementDataFormat(Worksheet $sheet, int $row, string $column, array $attributeArray): void { if (isset($attributeArray['data-format'])) { @@ -615,6 +636,7 @@ class Html extends BaseReader } } + /** @param string[] $attributeArray */ private function processDomElementThTd(Worksheet $sheet, int &$row, string &$column, string &$cellContent, DOMElement $child, array &$attributeArray): void { while (isset($this->rowspan[$column . $row])) { @@ -640,6 +662,7 @@ class Html extends BaseReader //create merging rowspan and colspan $columnTo = $column; for ($i = 0; $i < (int) $attributeArray['colspan'] - 1; ++$i) { + /** @var string $columnTo */ ++$columnTo; } $range = $column . $row . ':' . $columnTo . ($row + (int) $attributeArray['rowspan'] - 1); @@ -660,6 +683,7 @@ class Html extends BaseReader //create merging colspan $columnTo = $column; for ($i = 0; $i < (int) $attributeArray['colspan'] - 1; ++$i) { + /** @var string $columnTo */ ++$columnTo; } $sheet->mergeCells($column . $row . ':' . $columnTo . $row); @@ -667,7 +691,7 @@ class Html extends BaseReader $column = $columnTo; // ++$columnTo above confuses phpstan } - ++$column; + ++$column; //* @phpstan-ignore-line } protected function processDomElement(DOMNode $element, Worksheet $sheet, int &$row, string &$column, string &$cellContent): void @@ -792,6 +816,7 @@ class Html extends BaseReader } } + /** @param string[] $matches */ private static function replaceNonAscii(array $matches): string { return '&#' . mb_ord($matches[0], 'UTF-8') . ';'; @@ -891,6 +916,8 @@ class Html extends BaseReader * * TODO : * - Implement to other propertie, such as border + * + * @param string[] $attributeArray */ private function applyInlineStyle(Worksheet &$sheet, int $row, string $column, array $attributeArray): void { @@ -903,6 +930,7 @@ class Html extends BaseReader } elseif (isset($attributeArray['rowspan'], $attributeArray['colspan'])) { $columnTo = $column; for ($i = 0; $i < (int) $attributeArray['colspan'] - 1; ++$i) { + /** @var string $columnTo */ ++$columnTo; } $range = $column . $row . ':' . $columnTo . ($row + (int) $attributeArray['rowspan'] - 1); @@ -913,6 +941,7 @@ class Html extends BaseReader } elseif (isset($attributeArray['colspan'])) { $columnTo = $column; for ($i = 0; $i < (int) $attributeArray['colspan'] - 1; ++$i) { + /** @var string $columnTo */ ++$columnTo; } $range = $column . $row . ':' . $columnTo . $row; @@ -1079,6 +1108,7 @@ class Html extends BaseReader return HelperHtml::colourNameLookup($value); } + /** @param string[] $attributes */ private function insertImage(Worksheet $sheet, string $column, int $row, array $attributes): void { if (!isset($attributes['src'])) { @@ -1109,6 +1139,8 @@ class Html extends BaseReader $drawing->setName($name); } + /** @var null|scalar $width */ + /** @var null|scalar $height */ if ($width) { if ($height) { $drawing->setWidthAndHeight((int) $width, (int) $height); @@ -1135,6 +1167,11 @@ class Html extends BaseReader } } + /** + * @param string[] $attributes + * + * @return mixed[] + */ private static function getStyleArray(array $attributes): array { $styleArray = []; @@ -1183,6 +1220,7 @@ class Html extends BaseReader 'thick' => Border::BORDER_THICK, ]; + /** @return array */ public static function getBorderMappings(): array { return self::BORDER_MAPPINGS; diff --git a/src/PhpSpreadsheet/Reader/Xls.php b/src/PhpSpreadsheet/Reader/Xls.php index d1e3cdb99..ae0460361 100644 --- a/src/PhpSpreadsheet/Reader/Xls.php +++ b/src/PhpSpreadsheet/Reader/Xls.php @@ -104,6 +104,8 @@ class Xls extends XlsBase /** * Shared formats. + * + * @var mixed[] */ protected array $formats; @@ -116,36 +118,50 @@ class Xls extends XlsBase /** * Color palette. + * + * @var string[][] */ protected array $palette; /** * Worksheets. + * + * @var array */ protected array $sheets; /** * External books. + * + * @var mixed[][] */ protected array $externalBooks; /** * REF structures. Only applies to BIFF8. + * + * @var mixed[][] */ protected array $ref; /** * External names. + * + * @var array|string> */ protected array $externalNames; /** * Defined names. + * + * @var array{isBuiltInName: int, name: string, formula: string, scope: int} */ protected array $definedname; /** * Shared strings. Only applies to BIFF8. + * + * @var array */ protected array $sst; @@ -161,16 +177,22 @@ class Xls extends XlsBase /** * Objects. One OBJ record contributes with one entry. + * + * @var mixed[] */ protected array $objs; /** * Text Objects. One TXO record corresponds with one entry. + * + * @var array */ protected array $textObjects; /** * Cell Annotations (BIFF8). + * + * @var mixed[] */ protected array $cellNotes; @@ -191,22 +213,30 @@ class Xls extends XlsBase /** * Mapping of XF index (that is a cell XF) to final index in cellXf collection. + * + * @var int[] */ protected array $mapCellXfIndex; /** * Mapping of XF index (that is a style XF) to final index in cellStyleXf collection. + * + * @var int[] */ protected array $mapCellStyleXfIndex; /** * The shared formulas in a sheet. One SHAREDFMLA record contributes with one value. + * + * @var mixed[] */ protected array $sharedFormulas; /** * The shared formula parts in a sheet. One FORMULA record contributes with one value if it * refers to a shared formula. + * + * @var mixed[] */ protected array $sharedFormulaParts; @@ -220,6 +250,8 @@ class Xls extends XlsBase */ protected int $encryptionStartPos = 0; + protected string $encryptionPassword = 'VelvetSweatshop'; + /** * The current RC4 decryption object. */ @@ -232,7 +264,7 @@ class Xls extends XlsBase /** * The current MD5 context state. - * It is never set in the program, so code which uses it is suspect. + * It is set via call-by-reference to verifyPassword. */ private string $md5Ctxt = ''; @@ -721,10 +753,18 @@ class Xls extends XlsBase $cbRuns = self::getUInt2d($recordData, 12); $text = $this->getSplicedRecordData(); - $textByte = $text['spliceOffsets'][1] - $text['spliceOffsets'][0] - 1; - $textStr = substr($text['recordData'], $text['spliceOffsets'][0] + 1, $textByte); + /** @var int[] */ + $tempSplice = $text['spliceOffsets']; + /** @var int */ + $temp = $tempSplice[0]; + /** @var int */ + $temp1 = $tempSplice[1]; + $textByte = $temp1 - $temp - 1; + /** @var string */ + $textRecordData = $text['recordData']; + $textStr = substr($textRecordData, $temp + 1, $textByte); // get 1 byte - $is16Bit = ord($text['recordData'][0]); + $is16Bit = ord($textRecordData[0]); // it is possible to use a compressed format, // which omits the high bytes of all characters, if they are all zero if (($is16Bit & 0x01) === 0) { @@ -735,7 +775,7 @@ class Xls extends XlsBase $this->textObjects[$this->textObjRef] = [ 'text' => $textStr, - 'format' => substr($text['recordData'], $text['spliceOffsets'][1], $cbRuns), + 'format' => substr($textRecordData, $tempSplice[1], $cbRuns), 'alignment' => $grbitOpts, 'rotation' => $rot, ]; @@ -780,6 +820,13 @@ class Xls extends XlsBase } } + public function setEncryptionPassword(string $encryptionPassword): self + { + $this->encryptionPassword = $encryptionPassword; + + return $this; + } + /** * FILEPASS. * @@ -799,7 +846,7 @@ class Xls extends XlsBase { $length = self::getUInt2d($this->data, $this->pos + 2); - if ($length != 54) { + if ($length < 54) { throw new Exception('Unexpected file pass record length'); } @@ -808,7 +855,10 @@ class Xls extends XlsBase // move stream pointer to next record $this->pos += 4 + $length; - if (!$this->verifyPassword('VelvetSweatshop', substr($recordData, 6, 16), substr($recordData, 22, 16), substr($recordData, 38, 16), $this->md5Ctxt)) { + if (substr($recordData, 0, 2) !== "\x01\x00" || substr($recordData, 4, 2) !== "\x01\x00") { + throw new Exception('Unsupported encryption algorithm'); + } + if (!$this->verifyPassword($this->encryptionPassword, substr($recordData, 6, 16), substr($recordData, 22, 16), substr($recordData, 38, 16), $this->md5Ctxt)) { throw new Exception('Decryption password incorrect'); } @@ -1046,6 +1096,7 @@ class Xls extends XlsBase } else { $string = $this->readByteStringShort(substr($recordData, 14)); } + /** @var string[] $string */ $objFont->setName($string['value']); $this->objFonts[] = $objFont; @@ -1142,7 +1193,9 @@ class Xls extends XlsBase // we set the general format code $numberFormat = ['formatCode' => NumberFormat::FORMAT_GENERAL]; } - $objStyle->getNumberFormat()->setFormatCode($numberFormat['formatCode']); + /** @var string[] $numberFormat */ + $objStyle->getNumberFormat() + ->setFormatCode($numberFormat['formatCode']); // offset: 4; size: 2; XF type, cell protection, and parent style XF // bit 2-0; mask 0x0007; XF_TYPE_PROT @@ -1632,7 +1685,7 @@ class Xls extends XlsBase $string = $this->readByteStringShort(substr($recordData, 6)); $rec_name = $string['value']; } - + /** @var string $rec_name */ $this->sheets[] = [ 'name' => $rec_name, 'offset' => $rec_offset, @@ -1837,6 +1890,7 @@ class Xls extends XlsBase // get spliced record data $splicedRecordData = $this->getSplicedRecordData(); + /** @var string */ $recordData = $splicedRecordData['recordData']; $this->drawingGroupData .= $recordData; @@ -1865,12 +1919,14 @@ class Xls extends XlsBase $splicedRecordData = $this->getSplicedRecordData(); $recordData = $splicedRecordData['recordData']; + /** @var mixed[] */ $spliceOffsets = $splicedRecordData['spliceOffsets']; // offset: 0; size: 4; total number of strings in the workbook $pos += 4; // offset: 4; size: 4; number of following strings ($nm) + /** @var string $recordData */ $nm = self::getInt4d($recordData, 4); $pos += 4; @@ -1886,10 +1942,13 @@ class Xls extends XlsBase // loop through the Unicode strings (16-bit length) for ($i = 0; $i < $nm && $pos < $limitposSST; ++$i) { // number of characters in the Unicode string + /** @var int $pos */ $numChars = self::getUInt2d($recordData, $pos); + /** @var int $pos */ $pos += 2; // option flags + /** @var string $recordData */ $optionFlags = ord($recordData[$pos]); ++$pos; @@ -1931,6 +1990,7 @@ class Xls extends XlsBase } } + /** @var int $limitpos */ if ($pos + $len <= $limitpos) { // character array is not split between records @@ -1963,11 +2023,14 @@ class Xls extends XlsBase // repeated option flags // OpenOffice.org documentation 5.21 $option = ord($recordData[$pos]); + /** @var int $pos */ ++$pos; + /** @var int $limitpos */ if ($isCompressed && ($option == 0)) { // 1st fragment compressed // this fragment compressed + /** @var int */ $len = min($charsLeft, $limitpos - $pos); $retstr .= substr($recordData, $pos, $len); $charsLeft -= $len; @@ -1975,6 +2038,7 @@ class Xls extends XlsBase } elseif (!$isCompressed && ($option != 0)) { // 1st fragment uncompressed // this fragment uncompressed + /** @var int */ $len = min($charsLeft * 2, $limitpos - $pos); $retstr .= substr($recordData, $pos, $len); $charsLeft -= $len / 2; @@ -1998,6 +2062,7 @@ class Xls extends XlsBase $newstr .= $retstr[$j] . chr(0); } $retstr = $newstr; + /** @var int */ $len = min($charsLeft * 2, $limitpos - $pos); $retstr .= substr($recordData, $pos, $len); $charsLeft -= $len / 2; @@ -2017,6 +2082,7 @@ class Xls extends XlsBase // list of formatting runs for ($j = 0; $j < $formattingRuns; ++$j) { // first formatted character; zero-based + /** @var int $pos */ $charPos = self::getUInt2d($recordData, $pos + $j * 4); // index to font record @@ -2182,8 +2248,13 @@ class Xls extends XlsBase $string = $this->readByteStringShort($recordData); } - $this->phpSheet->getHeaderFooter()->setOddHeader($string['value']); - $this->phpSheet->getHeaderFooter()->setEvenHeader($string['value']); + /** @var string[] $string */ + $this->phpSheet + ->getHeaderFooter() + ->setOddHeader($string['value']); + $this->phpSheet + ->getHeaderFooter() + ->setEvenHeader($string['value']); } } } @@ -2208,8 +2279,14 @@ class Xls extends XlsBase } else { $string = $this->readByteStringShort($recordData); } - $this->phpSheet->getHeaderFooter()->setOddFooter($string['value']); - $this->phpSheet->getHeaderFooter()->setEvenFooter($string['value']); + /** @var string */ + $temp = $string['value']; + $this->phpSheet + ->getHeaderFooter() + ->setOddFooter($temp); + $this->phpSheet + ->getHeaderFooter() + ->setEvenFooter($temp); } } } @@ -2689,9 +2766,14 @@ class Xls extends XlsBase $charPos = 0; $sstCount = count($this->sst[$index]['fmtRuns']); for ($i = 0; $i <= $sstCount; ++$i) { + /** @var mixed[][] $fmtRuns */ if (isset($fmtRuns[$i])) { - $text = StringHelper::substring($this->sst[$index]['value'], $charPos, $fmtRuns[$i]['charPos'] - $charPos); - $charPos = $fmtRuns[$i]['charPos']; + /** @var int[] */ + $temp = $fmtRuns[$i]; + $temp = $temp['charPos']; + /** @var int $charPos */ + $text = StringHelper::substring($this->sst[$index]['value'], $charPos, $temp - $charPos); + $charPos = $temp; } else { $text = StringHelper::substring($this->sst[$index]['value'], $charPos, StringHelper::countCharacters($this->sst[$index]['value'])); } @@ -2701,13 +2783,16 @@ class Xls extends XlsBase $richText->createText($text); } else { $textRun = $richText->createTextRun($text); + /** @var int[][] $fmtRuns */ if (isset($fmtRuns[$i - 1])) { if ($fmtRuns[$i - 1]['fontIndex'] < 4) { $fontIndex = $fmtRuns[$i - 1]['fontIndex']; } else { // this has to do with that index 4 is omitted in all BIFF versions for some stra nge reason // check the OpenOffice documentation of the FONT record - $fontIndex = $fmtRuns[$i - 1]['fontIndex'] - 1; + /** @var int */ + $temp = $fmtRuns[$i - 1]['fontIndex']; + $fontIndex = $temp - 1; } if (array_key_exists($fontIndex, $this->objFonts) === false) { $fontIndex = count($this->objFonts) - 1; @@ -3015,6 +3100,7 @@ class Xls extends XlsBase $string = $this->readByteStringLong($recordData); $value = $string['value']; } + /** @var string $value */ return $value; } @@ -3158,6 +3244,7 @@ class Xls extends XlsBase $string = $this->readByteStringLong(substr($recordData, 6)); $value = $string['value']; } + /** @var string $value */ if ($this->readEmptyCells || trim($value) !== '') { $cell = $this->phpSheet->getCell($columnString . ($row + 1)); $cell->setValueExplicit($value, DataType::TYPE_STRING); @@ -3211,7 +3298,7 @@ class Xls extends XlsBase $splicedRecordData = $this->getSplicedRecordData(); $recordData = $splicedRecordData['recordData']; - $this->drawingData .= $recordData; + $this->drawingData .= StringHelper::convertToString($recordData); } /** @@ -3491,6 +3578,7 @@ class Xls extends XlsBase ++$rangeBoundaries[1][0]; for ($row = $rangeBoundaries[0][1]; $row <= $rangeBoundaries[1][1]; ++$row) { for ($column = $rangeBoundaries[0][0]; $column != $rangeBoundaries[1][0]; ++$column) { + /** @var string $column */ if ($this->getReadFilter()->readCell($column, $row, $this->phpSheet->getTitle())) { $includeCellRange = true; @@ -3522,6 +3610,7 @@ class Xls extends XlsBase if ($this->version == self::XLS_BIFF8 && !$this->readDataOnly) { $cellRangeAddressList = Xls\Biff8::readBIFF8CellRangeAddressList($recordData); foreach ($cellRangeAddressList['cellRangeAddresses'] as $cellRangeAddress) { + /** @var string $cellRangeAddress */ if ( (str_contains($cellRangeAddress, ':')) && ($this->includeCellRangeFiltered($cellRangeAddress)) @@ -3750,6 +3839,7 @@ class Xls extends XlsBase case 0x14: // offset: 16; size: 2; color index for sheet tab $colorIndex = self::getUInt2d($recordData, 16); + /** @var string[] */ $color = Xls\Color::map($colorIndex, $this->palette, $this->version); $this->phpSheet->getTabColor()->setRGB($color['rgb']); @@ -3964,7 +4054,7 @@ class Xls extends XlsBase if (in_array($splitPoint, $validSplitPoints)) { // get spliced record data (and move pointer to next record) $splicedRecordData = $this->getSplicedRecordData(); - $this->drawingData .= $splicedRecordData['recordData']; + $this->drawingData .= StringHelper::convertToString($splicedRecordData['recordData']); return; } @@ -3978,6 +4068,8 @@ class Xls extends XlsBase * records are found. Splices the record data pieces and returns the combined string as if record data * is in one piece. * Moves to next current position in data stream to start of next record different from a CONtINUE record. + * + * @return mixed[] */ private function getSplicedRecordData(): array { @@ -4050,6 +4142,7 @@ class Xls extends XlsBase while ($formulaData !== '' && $token = $this->getNextToken($formulaData, $baseCell)) { $tokens[] = $token; + /** @var int[] $token */ $formulaData = substr($formulaData, $token['size']); } @@ -4061,6 +4154,7 @@ class Xls extends XlsBase /** * Take array of tokens together with additional data for formula and return human readable formula. * + * @param mixed[][] $tokens * @param string $additionalData Additional binary data going with the formula * * @return string Human readable formula @@ -4081,7 +4175,8 @@ class Xls extends XlsBase $space3 = $space3 ?? ''; // carriage returns before opening parenthesis $space4 = $space4 ?? ''; // spaces before closing parenthesis $space5 = $space5 ?? ''; // carriage returns before closing parenthesis - + /** @var string */ + $tokenData = $token['data'] ?? ''; switch ($token['name']) { case 'tAdd': // addition case 'tConcat': // addition @@ -4100,20 +4195,20 @@ class Xls extends XlsBase case 'tSub': // subtraction $op2 = array_pop($formulaStrings); $op1 = array_pop($formulaStrings); - $formulaStrings[] = "$op1$space1$space0{$token['data']}$op2"; + $formulaStrings[] = "$op1$space1$space0{$tokenData}$op2"; unset($space0, $space1); break; case 'tUplus': // unary plus case 'tUminus': // unary minus $op = array_pop($formulaStrings); - $formulaStrings[] = "$space1$space0{$token['data']}$op"; + $formulaStrings[] = "$space1$space0{$tokenData}$op"; unset($space0, $space1); break; case 'tPercent': // percent sign $op = array_pop($formulaStrings); - $formulaStrings[] = "$op$space1$space0{$token['data']}"; + $formulaStrings[] = "$op$space1$space0{$tokenData}"; unset($space0, $space1); break; @@ -4126,29 +4221,30 @@ class Xls extends XlsBase break; case 'tAttrSpace': // space / carriage return // space will be used when next token arrives, do not alter formulaString stack + /** @var string[][] $token */ switch ($token['data']['spacetype']) { case 'type0': - $space0 = str_repeat(' ', $token['data']['spacecount']); + $space0 = str_repeat(' ', (int) $token['data']['spacecount']); break; case 'type1': - $space1 = str_repeat("\n", $token['data']['spacecount']); + $space1 = str_repeat("\n", (int) $token['data']['spacecount']); break; case 'type2': - $space2 = str_repeat(' ', $token['data']['spacecount']); + $space2 = str_repeat(' ', (int) $token['data']['spacecount']); break; case 'type3': - $space3 = str_repeat("\n", $token['data']['spacecount']); + $space3 = str_repeat("\n", (int) $token['data']['spacecount']); break; case 'type4': - $space4 = str_repeat(' ', $token['data']['spacecount']); + $space4 = str_repeat(' ', (int) $token['data']['spacecount']); break; case 'type5': - $space5 = str_repeat("\n", $token['data']['spacecount']); + $space5 = str_repeat("\n", (int) $token['data']['spacecount']); break; } @@ -4162,19 +4258,25 @@ class Xls extends XlsBase break; case 'tFunc': // function with fixed number of arguments case 'tFuncV': // function with variable number of arguments - if ($token['data']['function'] != '') { + /** @var string[] */ + $temp1 = $token['data']; + $temp2 = $temp1['function']; + if ($temp2 != '') { // normal function $ops = []; // array of operators - for ($i = 0; $i < $token['data']['args']; ++$i) { + $temp3 = (int) $temp1['args']; + for ($i = 0; $i < $temp3; ++$i) { $ops[] = array_pop($formulaStrings); } $ops = array_reverse($ops); - $formulaStrings[] = "$space1$space0{$token['data']['function']}(" . implode(',', $ops) . ')'; + $formulaStrings[] = "$space1$space0{$temp2}(" . implode(',', $ops) . ')'; unset($space0, $space1); } else { // add-in function $ops = []; // array of operators - for ($i = 0; $i < $token['data']['args'] - 1; ++$i) { + /** @var int[] */ + $temp = $token['data']; + for ($i = 0; $i < $temp['args'] - 1; ++$i) { $ops[] = array_pop($formulaStrings); } $ops = array_reverse($ops); @@ -4201,7 +4303,7 @@ class Xls extends XlsBase // bite off chunk of additional data $cellRangeAddressList = Xls\Biff8::readBIFF8CellRangeAddressList($additionalData); $additionalData = substr($additionalData, $cellRangeAddressList['size']); - $formulaStrings[] = "$space1$space0{$token['data']}"; + $formulaStrings[] = "$space1$space0{$tokenData}"; unset($space0, $space1); break; @@ -4221,7 +4323,7 @@ class Xls extends XlsBase case 'tRefN': case 'tAreaN': case 'tStr': // string - $formulaStrings[] = "$space1$space0{$token['data']}"; + $formulaStrings[] = "$space1$space0{$tokenData}"; unset($space0, $space1); break; @@ -4237,6 +4339,8 @@ class Xls extends XlsBase * * @param string $formulaData Formula data * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas + * + * @return mixed[] */ private function getNextToken(string $formulaData, string $baseCell = 'A1'): array { @@ -4510,7 +4614,8 @@ class Xls extends XlsBase // offset: 1; size: 2; one-based index to definedname record $definedNameIndex = self::getUInt2d($formulaData, 1) - 1; // offset: 2; size: 2; not used - $data = $this->definedname[$definedNameIndex]['name'] ?? ''; + /** @var string[] */ + $data = $this->definedname[$definedNameIndex]['name'] ?? ''; //* @phpstan-ignore-line break; case 0x24: // single cell reference e.g. A5 @@ -4694,6 +4799,8 @@ class Xls extends XlsBase /** * Read byte string (8-bit string length) * OpenOffice documentation: 2.5.2. + * + * @return array{value: mixed, size: int} */ protected function readByteStringShort(string $subData): array { @@ -4712,6 +4819,8 @@ class Xls extends XlsBase /** * Read byte string (16-bit string length) * OpenOffice documentation: 2.5.2. + * + * @return array{value: mixed, size: int} */ protected function readByteStringLong(string $subData): array { @@ -4742,6 +4851,8 @@ class Xls extends XlsBase * For now, however, this function makes it readable, * which satisfies Phpstan. * + * @return mixed[] + * * @codeCoverageIgnore */ public function getMapCellStyleXfIndex(): array @@ -4753,12 +4864,15 @@ class Xls extends XlsBase * Parse conditional formatting blocks. * * @see https://www.openoffice.org/sc/excelfileformat.pdf Search for CFHEADER followed by CFRULE + * + * @return mixed[] */ protected function readCFHeader(): array { return (new Xls\ConditionalFormatting())->readCFHeader2($this); } + /** @param string[] $cellRangeAddresses */ protected function readCFRule(array $cellRangeAddresses): void { (new Xls\ConditionalFormatting())->readCFRule2($cellRangeAddresses, $this); diff --git a/src/PhpSpreadsheet/Reader/Xls/Biff5.php b/src/PhpSpreadsheet/Reader/Xls/Biff5.php index ef9619eec..61ff9ee0b 100644 --- a/src/PhpSpreadsheet/Reader/Xls/Biff5.php +++ b/src/PhpSpreadsheet/Reader/Xls/Biff5.php @@ -46,6 +46,8 @@ class Biff5 extends Xls /** * Read BIFF5 cell range address list * section 2.5.15. + * + * @return array{size: int, cellRangeAddresses: string[]} */ public static function readBIFF5CellRangeAddressList(string $subData): array { diff --git a/src/PhpSpreadsheet/Reader/Xls/Biff8.php b/src/PhpSpreadsheet/Reader/Xls/Biff8.php index f95c0b5ea..2de9fb8c3 100644 --- a/src/PhpSpreadsheet/Reader/Xls/Biff8.php +++ b/src/PhpSpreadsheet/Reader/Xls/Biff8.php @@ -12,6 +12,8 @@ class Biff8 extends Xls * read BIFF8 constant value array from array data * returns e.g. ['value' => '{1,2;3,4}', 'size' => 40] * section 2.5.8. + * + * @return array{value: string, size: int} */ protected static function readBIFF8ConstantArray(string $arrayData): array { @@ -47,6 +49,8 @@ class Biff8 extends Xls * read BIFF8 constant value which may be 'Empty Value', 'Number', 'String Value', 'Boolean Value', 'Error Value' * section 2.5.7 * returns e.g. ['value' => '5', 'size' => 9]. + * + * @return array{value: bool|float|int|string, size: int} */ private static function readBIFF8Constant(string $valueData): array { @@ -101,6 +105,8 @@ class Biff8 extends Xls /** * Read BIFF8 cell range address list * section 2.5.15. + * + * @return array{size: int, cellRangeAddresses: mixed[]} */ public static function readBIFF8CellRangeAddressList(string $subData): array { diff --git a/src/PhpSpreadsheet/Reader/Xls/Color.php b/src/PhpSpreadsheet/Reader/Xls/Color.php index 17b6e165c..adbe1a251 100644 --- a/src/PhpSpreadsheet/Reader/Xls/Color.php +++ b/src/PhpSpreadsheet/Reader/Xls/Color.php @@ -10,9 +10,9 @@ class Color * Read color. * * @param int $color Indexed color - * @param array $palette Color palette + * @param string[][] $palette Color palette * - * @return array RGB color value, example: ['rgb' => 'FF0000'] + * @return string[] RGB color value, example: ['rgb' => 'FF0000'] */ public static function map(int $color, array $palette, int $version): array { diff --git a/src/PhpSpreadsheet/Reader/Xls/Color/BIFF5.php b/src/PhpSpreadsheet/Reader/Xls/Color/BIFF5.php index 2c0790c9c..ecc026c38 100644 --- a/src/PhpSpreadsheet/Reader/Xls/Color/BIFF5.php +++ b/src/PhpSpreadsheet/Reader/Xls/Color/BIFF5.php @@ -65,6 +65,8 @@ class BIFF5 /** * Map color array from BIFF5 built-in color index. + * + * @return array{rgb: string} */ public static function lookup(int $color): array { diff --git a/src/PhpSpreadsheet/Reader/Xls/Color/BIFF8.php b/src/PhpSpreadsheet/Reader/Xls/Color/BIFF8.php index 914034df2..11745f797 100644 --- a/src/PhpSpreadsheet/Reader/Xls/Color/BIFF8.php +++ b/src/PhpSpreadsheet/Reader/Xls/Color/BIFF8.php @@ -65,6 +65,8 @@ class BIFF8 /** * Map color array from BIFF8 built-in color index. + * + * @return array{rgb: string} */ public static function lookup(int $color): array { diff --git a/src/PhpSpreadsheet/Reader/Xls/Color/BuiltIn.php b/src/PhpSpreadsheet/Reader/Xls/Color/BuiltIn.php index a715b110b..575244645 100644 --- a/src/PhpSpreadsheet/Reader/Xls/Color/BuiltIn.php +++ b/src/PhpSpreadsheet/Reader/Xls/Color/BuiltIn.php @@ -21,6 +21,8 @@ class BuiltIn * Map built-in color to RGB value. * * @param int $color Indexed color + * + * @return array{rgb: string} */ public static function lookup(int $color): array { diff --git a/src/PhpSpreadsheet/Reader/Xls/ConditionalFormatting.php b/src/PhpSpreadsheet/Reader/Xls/ConditionalFormatting.php index 1c05c63c7..9f89d1620 100644 --- a/src/PhpSpreadsheet/Reader/Xls/ConditionalFormatting.php +++ b/src/PhpSpreadsheet/Reader/Xls/ConditionalFormatting.php @@ -48,6 +48,8 @@ class ConditionalFormatting extends Xls * Parse conditional formatting blocks. * * @see https://www.openoffice.org/sc/excelfileformat.pdf Search for CFHEADER followed by CFRULE + * + * @return mixed[] */ protected function readCFHeader2(Xls $xls): array { @@ -73,6 +75,7 @@ class ConditionalFormatting extends Xls return $cellRangeAddresses; } + /** @param string[] $cellRangeAddresses */ protected function readCFRule2(array $cellRangeAddresses, Xls $xls): void { $length = self::getUInt2d($xls->data, $xls->pos + 2); @@ -212,7 +215,9 @@ class ConditionalFormatting extends Xls $color = self::getInt4d($options, 80); if ($color !== -1) { - $style->getFont()->getColor()->setRGB(Color::map($color, $xls->palette, $xls->version)['rgb']); + $style->getFont() + ->getColor() + ->setRGB(Color::map($color, $xls->palette, $xls->version)['rgb']); } } @@ -222,6 +227,7 @@ class ConditionalFormatting extends Xls private function getCFBorderStyle(string $options, Style $style, bool $hasBorderLeft, bool $hasBorderRight, bool $hasBorderTop, bool $hasBorderBottom, Xls $xls): void { + /** @var false|int[] */ $valueArray = unpack('V', $options); $value = is_array($valueArray) ? $valueArray[1] : 0; $left = $value & 15; @@ -230,6 +236,7 @@ class ConditionalFormatting extends Xls $bottom = ($value >> 12) & 15; $leftc = ($value >> 16) & 0x7F; $rightc = ($value >> 23) & 0x7F; + /** @var false|int[] */ $valueArray = unpack('V', substr($options, 4)); $value = is_array($valueArray) ? $valueArray[1] : 0; $topc = $value & 0x7F; @@ -308,6 +315,7 @@ class ConditionalFormatting extends Xls } } + /** @param string[] $cellRanges */ private function setCFRules(array $cellRanges, string $type, string $operator, null|float|int|string $formula1, null|float|int|string $formula2, Style $style, bool $noFormatSet, Xls $xls): void { foreach ($cellRanges as $cellRange) { @@ -324,10 +332,14 @@ class ConditionalFormatting extends Xls } $conditional->setStyle($style); - $conditionalStyles = $xls->phpSheet->getStyle($cellRange)->getConditionalStyles(); + $conditionalStyles = $xls->phpSheet + ->getStyle($cellRange) + ->getConditionalStyles(); $conditionalStyles[] = $conditional; - $xls->phpSheet->getStyle($cellRange)->setConditionalStyles($conditionalStyles); + $xls->phpSheet + ->getStyle($cellRange) + ->setConditionalStyles($conditionalStyles); } } } diff --git a/src/PhpSpreadsheet/Reader/Xls/DataValidationHelper.php b/src/PhpSpreadsheet/Reader/Xls/DataValidationHelper.php index e3a8d98c1..b5a945444 100644 --- a/src/PhpSpreadsheet/Reader/Xls/DataValidationHelper.php +++ b/src/PhpSpreadsheet/Reader/Xls/DataValidationHelper.php @@ -176,6 +176,7 @@ class DataValidationHelper extends Xls // offset: var; size: var; cell range address list with $cellRangeAddressList = Biff8::readBIFF8CellRangeAddressList(substr($recordData, $offset)); + /** @var string[] */ $cellRangeAddresses = $cellRangeAddressList['cellRangeAddresses']; $maxRow = (string) AddressRange::MAX_ROW; $maxCol = AddressRange::MAX_COLUMN; diff --git a/src/PhpSpreadsheet/Reader/Xls/ListFunctions.php b/src/PhpSpreadsheet/Reader/Xls/ListFunctions.php index 9d3eeaba7..cd1c5cae9 100644 --- a/src/PhpSpreadsheet/Reader/Xls/ListFunctions.php +++ b/src/PhpSpreadsheet/Reader/Xls/ListFunctions.php @@ -48,7 +48,7 @@ class ListFunctions extends Xls } foreach ($xls->sheets as $sheet) { - if ($sheet['sheetType'] === 0x00 && is_string($sheet['name'])) { + if ($sheet['sheetType'] === 0x00) { // 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module $worksheetNames[] = $sheet['name']; } diff --git a/src/PhpSpreadsheet/Reader/Xls/LoadSpreadsheet.php b/src/PhpSpreadsheet/Reader/Xls/LoadSpreadsheet.php index cf99d472c..60fc5a125 100644 --- a/src/PhpSpreadsheet/Reader/Xls/LoadSpreadsheet.php +++ b/src/PhpSpreadsheet/Reader/Xls/LoadSpreadsheet.php @@ -52,7 +52,7 @@ class LoadSpreadsheet extends Xls $xls->sheets = []; $xls->externalBooks = []; $xls->ref = []; - $xls->definedname = []; + $xls->definedname = []; //* @phpstan-ignore-line $xls->sst = []; $xls->drawingGroupData = ''; $xls->xfIndex = 0; @@ -382,6 +382,7 @@ class LoadSpreadsheet extends Xls break; case self::XLS_TYPE_CFHEADER: + /** @var string[] */ $cellRangeAddresses = $xls->readCFHeader(); break; @@ -464,6 +465,7 @@ class LoadSpreadsheet extends Xls $offsetX = (int) ($startOffsetX * SharedXls::sizeCol($xls->phpSheet, $startColumn) / 1024); $offsetY = (int) ($startOffsetY * SharedXls::sizeRow($xls->phpSheet, $startRow) / 256); + /** @var int[] $obj */ switch ($obj['otObjType']) { case 0x19: // Note @@ -472,7 +474,7 @@ class LoadSpreadsheet extends Xls if (isset($xls->textObjects[$obj['idObjID']])) { $textObject = $xls->textObjects[$obj['idObjID']]; - $xls->cellNotes[$obj['idObjID']]['objTextData'] = $textObject; + $xls->cellNotes[$obj['idObjID']]['objTextData'] = $textObject; //* @phpstan-ignore-line } } @@ -492,6 +494,7 @@ class LoadSpreadsheet extends Xls } if ($escherWorkbook) { + /** @var BSE[] */ $BSECollection = method_exists($escherWorkbook, 'getDggContainer') ? $escherWorkbook->getDggContainer()->getBstoreContainer()->getBSECollection() : []; $BSE = $BSECollection[$BSEindex - 1]; $blipType = $BSE->getBlipType(); @@ -545,7 +548,9 @@ class LoadSpreadsheet extends Xls /** @var int $row */ [$column, $row] = Coordinate::coordinateFromString($cell); if ($xls->getReadFilter()->readCell($column, $row, $xls->phpSheet->getTitle())) { - $formula = $xls->getFormulaFromStructure($xls->sharedFormulas[$baseCell], $cell); + /** @var string */ + $temp = $xls->sharedFormulas[$baseCell]; + $formula = $xls->getFormulaFromStructure($temp, $cell); $xls->phpSheet->getCell($cell)->setValueExplicit('=' . $formula, DataType::TYPE_FORMULA); } } @@ -553,6 +558,7 @@ class LoadSpreadsheet extends Xls if (!empty($xls->cellNotes)) { foreach ($xls->cellNotes as $note => $noteDetails) { + /** @var array{author: string, cellRef: string, objTextData?: mixed[]} $noteDetails */ if (!isset($noteDetails['objTextData'])) { if (isset($xls->textObjects[$note])) { $textObject = $xls->textObjects[$note]; @@ -562,7 +568,14 @@ class LoadSpreadsheet extends Xls } } $cellAddress = str_replace('$', '', $noteDetails['cellRef']); - $xls->phpSheet->getComment($cellAddress)->setAuthor($noteDetails['author'])->setText($xls->parseRichText($noteDetails['objTextData']['text'])); + /** @var string */ + $tempDetails = $noteDetails['objTextData']['text']; + $xls->phpSheet + ->getComment($cellAddress) + ->setAuthor($noteDetails['author']) + ->setText( + $xls->parseRichText($tempDetails) + ); } } if ($selectedCells !== '') { @@ -575,6 +588,7 @@ class LoadSpreadsheet extends Xls // add the named ranges (defined names) foreach ($xls->definedname as $definedName) { + /** @var array{isBuiltInName: int, name: string, formula: string, scope: int} $definedName */ if ($definedName['isBuiltInName']) { switch ($definedName['name']) { case pack('C', 0x06): @@ -647,7 +661,6 @@ class LoadSpreadsheet extends Xls } } else { // Extract range - /** @var non-empty-string $formula */ $formula = $definedName['formula']; if (str_contains($formula, '!')) { $explodes = Worksheet::extractSheetTitle($formula, true, true); diff --git a/src/PhpSpreadsheet/Reader/Xls/MD5.php b/src/PhpSpreadsheet/Reader/Xls/MD5.php index 7da2eeee5..56dd4a322 100644 --- a/src/PhpSpreadsheet/Reader/Xls/MD5.php +++ b/src/PhpSpreadsheet/Reader/Xls/MD5.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Reader\Xls; +use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException; + class MD5 { private int $a; @@ -58,8 +60,9 @@ class MD5 */ public function add(string $data): void { - // @phpstan-ignore-next-line - $words = array_values(unpack('V16', $data)); + $unpacked = unpack('V16', $data) ?: throw new ReaderException('unable to unpack data'); + /** @var int[] */ + $words = array_values($unpacked); $A = $this->a; $B = $this->b; @@ -173,7 +176,9 @@ class MD5 private static function step(callable $func, int &$A, int $B, int $C, int $D, int $M, int $s, $t): void { $t = self::signedInt($t); - $A = (int) ($A + call_user_func($func, $B, $C, $D) + $M + $t) & self::$allOneBits; + /** @var int */ + $temp = call_user_func($func, $B, $C, $D); + $A = (int) ($A + $temp + $M + $t) & self::$allOneBits; $A = self::rotate($A, $s); $A = (int) ($B + $A) & self::$allOneBits; } diff --git a/src/PhpSpreadsheet/Reader/XlsBase.php b/src/PhpSpreadsheet/Reader/XlsBase.php index e6969db04..6f9da57ce 100644 --- a/src/PhpSpreadsheet/Reader/XlsBase.php +++ b/src/PhpSpreadsheet/Reader/XlsBase.php @@ -177,6 +177,8 @@ class XlsBase extends BaseReader * OpenOffice.org's Documentation of the Microsoft Excel File Format, section 2.5.4. * * @param string $rgb Encoded RGB value (4 bytes) + * + * @return array{rgb: string} */ protected static function readRGB(string $rgb): array { @@ -199,6 +201,8 @@ class XlsBase extends BaseReader * Extracts an Excel Unicode short string (8-bit string length) * OpenOffice documentation: 2.5.3 * function will automatically find out where the Unicode string ends. + * + * @return array{value: string, size: int} */ protected static function readUnicodeStringShort(string $subData): array { @@ -217,6 +221,8 @@ class XlsBase extends BaseReader * Extracts an Excel Unicode long string (16-bit string length) * OpenOffice documentation: 2.5.3 * this function is under construction, needs to support rich text, and Asian phonetic settings. + * + * @return array{value: string, size: int} */ protected static function readUnicodeStringLong(string $subData): array { @@ -235,6 +241,8 @@ class XlsBase extends BaseReader * Read Unicode string with no string length field, but with known character count * this function is under construction, needs to support rich text, and Asian phonetic settings * OpenOffice.org's Documentation of the Microsoft Excel File Format, section 2.5.3. + * + * @return array{value: string, size: int} */ protected static function readUnicodeString(string $subData, int $characterCount): array { diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index e687e4a2f..178f73bcc 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -38,6 +38,7 @@ use PhpOffice\PhpSpreadsheet\Style\Font as StyleFont; use PhpOffice\PhpSpreadsheet\Style\NumberFormat; use PhpOffice\PhpSpreadsheet\Style\Style; use PhpOffice\PhpSpreadsheet\Worksheet\HeaderFooterDrawing; +use PhpOffice\PhpSpreadsheet\Worksheet\Table\TableDxfsStyle; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; use SimpleXMLElement; use Throwable; @@ -57,6 +58,7 @@ class Xlsx extends BaseReader private Styles $styleReader; + /** @var SharedFormula[] */ private array $sharedFormulae = []; /** @@ -102,11 +104,13 @@ class Xlsx extends BaseReader } // Phpstan thinks, correctly, that xpath can return false. + /** @return mixed[] */ private static function xpathNoFalse(SimpleXMLElement $sxml, string $path): array { return self::falseToArray($sxml->xpath($path)); } + /** @return mixed[] */ public static function falseToArray(mixed $value): array { return is_array($value) ? $value : []; @@ -158,6 +162,8 @@ class Xlsx extends BaseReader /** * Reads names of the worksheets from a file, without parsing the whole file to a Spreadsheet object. + * + * @return string[] */ public function listWorksheetNames(string $filename): array { @@ -408,6 +414,7 @@ class Xlsx extends BaseReader $addingFirstCellStyleXf = true; $addingFirstCellXf = true; + /** @var mixed[][][][] */ $unparsedLoadedData = []; $this->zip = $zip = new ZipArchive(); @@ -602,11 +609,13 @@ class Xlsx extends BaseReader $numFmts = $xmlStyles->numFmts[0]; } if (isset($numFmts)) { + /** @var SimpleXMLElement $numFmts */ $numFmts->registerXPathNamespace('sml', $mainNS); } $this->styleReader->setNamespace($mainNS); if (!$this->readDataOnly/* && $xmlStyles*/) { foreach ($xfTags as $xfTag) { + /** @var SimpleXMLElement $xfTag */ $xf = self::getAttributes($xfTag); $numFmt = null; @@ -655,6 +664,7 @@ class Xlsx extends BaseReader } foreach ($cellXfTags as $xfTag) { + /** @var SimpleXMLElement $xfTag */ $xf = self::getAttributes($xfTag); $numFmt = NumberFormat::FORMAT_GENERAL; if ($numFmts && $xf['numFmtId']) { @@ -803,6 +813,7 @@ class Xlsx extends BaseReader $xmlSheetMain = $xmlSheetNS->children($mainNS); // Setting Conditional Styles adjusts selected cells, so we need to execute this // before reading the sheet view data to get the actual selected cells + /** @var Style[] $dxfs */ if (!$this->readDataOnly && ($xmlSheet->conditionalFormatting)) { (new ConditionalStyles($docSheet, $xmlSheet, $dxfs, $this->styleReader))->load(); } @@ -967,7 +978,7 @@ class Xlsx extends BaseReader $cAttrS = isset($styles[$cAttrS]) ? $cAttrS : 0; $cell->setXfIndex($cAttrS); // issue 3495 - if ($cellDataType === DataType::TYPE_FORMULA && $styles[$cAttrS]->quotePrefix === true) { + if ($cellDataType === DataType::TYPE_FORMULA && $styles[$cAttrS]->quotePrefix === true) { //* @phpstan-ignore-line $holdSelected = $docSheet->getSelectedCells(); $cell->getStyle()->setQuotePrefix(false); $docSheet->setSelectedCells($holdSelected); @@ -1059,6 +1070,7 @@ class Xlsx extends BaseReader if ($mc->AlternateContent) { foreach ($mc->AlternateContent as $alternateContent) { $alternateContent = self::testSimpleXml($alternateContent); + /** @var mixed[][][][] $unparsedLoadedData */ $unparsedLoadedData['sheets'][$docSheet->getCodeName()]['AlternateContents'][] = $alternateContent->asXML(); } } @@ -1111,18 +1123,23 @@ class Xlsx extends BaseReader $commentsFile->registerXpathNamespace('com', $mainNS); $authorPath = self::xpathNoFalse($commentsFile, 'com:authors/com:author'); foreach ($authorPath as $author) { + /** @var SimpleXMLElement $author */ $authors[] = (string) $author; } // Loop through contents $contentPath = self::xpathNoFalse($commentsFile, 'com:commentList/com:comment'); foreach ($contentPath as $comment) { + /** @var SimpleXMLElement $comment */ $commentx = $comment->attributes(); + /** @var array{ref: scalar, authorId?: scalar} $commentx */ $commentModel = $docSheet->getComment((string) $commentx['ref']); if (isset($commentx['authorId'])) { $commentModel->setAuthor($authors[(int) $commentx['authorId']]); } - $commentModel->setText($this->parseRichText($comment->children($mainNS)->text)); + /** @var SimpleXMLElement */ + $temp = $comment->children($mainNS); + $commentModel->setText($this->parseRichText($temp->text)); } } @@ -1160,6 +1177,7 @@ class Xlsx extends BaseReader $shapes = self::xpathNoFalse($vmlCommentsFile, '//v:shape'); foreach ($shapes as $shape) { + /** @var SimpleXMLElement $shape */ $shape->registerXPathNamespace('v', Namespaces::URN_VML); if (isset($shape['style'])) { @@ -1276,7 +1294,9 @@ class Xlsx extends BaseReader // unparsed vmlDrawing if ($unparsedVmlDrawings) { foreach ($unparsedVmlDrawings as $rId => $relPath) { + /** @var mixed[][][] $unparsedLoadedData */ $rId = substr($rId, 3); // rIdXXX + /** @var mixed[][] */ $unparsedVmlDrawing = &$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['vmlDrawings']; $unparsedVmlDrawing[$rId] = []; $unparsedVmlDrawing[$rId]['filePath'] = self::dirAdd("$dir/$fileWorksheet", $relPath); @@ -1324,6 +1344,7 @@ class Xlsx extends BaseReader $shapes = self::xpathNoFalse($vmlDrawing, '//v:shape'); foreach ($shapes as $idx => $shape) { + /** @var SimpleXMLElement $shape */ $shape->registerXPathNamespace('v', Namespaces::URN_VML); $imageData = $shape->xpath('//v:imagedata'); @@ -1334,6 +1355,7 @@ class Xlsx extends BaseReader $imageData = $imageData[$idx]; $imageData = self::getAttributes($imageData, Namespaces::URN_MSOFFICE); + /** @var array{width: int, height: int, margin-left?: int, margin-top: int} */ $style = self::toCSSArray((string) $shape['style']); if (array_key_exists((string) $imageData['relid'], $drawings)) { @@ -1668,6 +1690,7 @@ class Xlsx extends BaseReader } // store original rId of drawing files + /** @var mixed[][][][] $unparsedLoadedData */ $unparsedLoadedData['sheets'][$docSheet->getCodeName()]['drawingOriginalIds'] = []; foreach ($relsWorksheet->Relationship as $elex) { $ele = self::getAttributes($elex); @@ -1696,12 +1719,14 @@ class Xlsx extends BaseReader if ($xmlAltDrawing->AlternateContent) { foreach ($xmlAltDrawing->AlternateContent as $alternateContent) { $alternateContent = self::testSimpleXml($alternateContent); + /** @var mixed[][][][][] $unparsedLoadedData */ $unparsedLoadedData['sheets'][$docSheet->getCodeName()]['drawingAlternateContents'][] = $alternateContent->asXML(); } } } } + /** @var mixed[][][][] $unparsedLoadedData */ $this->readFormControlProperties($excel, $dir, $fileWorksheet, $docSheet, $unparsedLoadedData); $this->readPrinterSettings($excel, $dir, $fileWorksheet, $docSheet, $unparsedLoadedData); @@ -2044,11 +2069,13 @@ class Xlsx extends BaseReader } } + /** @param null|bool|mixed[]|SimpleXMLElement $array */ private static function getArrayItem(null|array|bool|SimpleXMLElement $array, int|string $key = 0): mixed { return ($array === null || is_bool($array)) ? null : ($array[$key] ?? null); } + /** @param null|bool|mixed[]|SimpleXMLElement $array */ private static function getArrayItemString(null|array|bool|SimpleXMLElement $array, int|string $key = 0): string { $retVal = self::getArrayItem($array, $key); @@ -2056,6 +2083,7 @@ class Xlsx extends BaseReader return StringHelper::convertToString($retVal, false); } + /** @param null|bool|mixed[]|SimpleXMLElement $array */ private static function getArrayItemIntOrSxml(null|array|bool|SimpleXMLElement $array, int|string $key = 0): int|SimpleXMLElement { $retVal = self::getArrayItem($array, $key); @@ -2071,6 +2099,7 @@ class Xlsx extends BaseReader return (string) preg_replace('~[^/]+/\.\./~', '', dirname($base) . "/$add"); } + /** @return mixed[] */ private static function toCSSArray(string $style): array { $style = self::stripWhiteSpaceFromStyleString($style); @@ -2116,6 +2145,7 @@ class Xlsx extends BaseReader return $value === 'true' || $value === 'TRUE'; } + /** @param string[] $hyperlinks */ private function readHyperLinkDrawing(\PhpOffice\PhpSpreadsheet\Worksheet\Drawing $objDrawing, SimpleXMLElement $cellAnchor, array $hyperlinks): void { $hlinkClick = $cellAnchor->pic->nvPicPr->cNvPr->children(Namespaces::DRAWINGML)->hlinkClick; @@ -2169,6 +2199,7 @@ class Xlsx extends BaseReader return $returnValue; } + /** @param mixed[][][][] $unparsedLoadedData */ private function readFormControlProperties(Spreadsheet $excel, string $dir, string $fileWorksheet, Worksheet $docSheet, array &$unparsedLoadedData): void { $zip = $this->zip; @@ -2185,6 +2216,7 @@ class Xlsx extends BaseReader } } + /** @var mixed[][] */ $unparsedCtrlProps = &$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['ctrlProps']; foreach ($ctrlProps as $rId => $ctrlProp) { $rId = substr($rId, 3); // rIdXXX @@ -2196,6 +2228,7 @@ class Xlsx extends BaseReader unset($unparsedCtrlProps); } + /** @param mixed[][][][] $unparsedLoadedData */ private function readPrinterSettings(Spreadsheet $excel, string $dir, string $fileWorksheet, Worksheet $docSheet, array &$unparsedLoadedData): void { $zip = $this->zip; @@ -2212,6 +2245,7 @@ class Xlsx extends BaseReader } } + /** @var mixed[][] */ $unparsedPrinterSettings = &$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['printerSettings']; foreach ($sheetPrinterSettings as $rId => $printerSettings) { $rId = substr($rId, 3); // rIdXXX @@ -2227,6 +2261,7 @@ class Xlsx extends BaseReader unset($unparsedPrinterSettings); } + /** @return array{string, string} */ private function getWorkbookBaseName(): array { $workbookBasename = ''; @@ -2308,6 +2343,10 @@ class Xlsx extends BaseReader } } + /** + * @param TableDxfsStyle[] $tableStyles + * @param mixed[] $dxfs + */ private function readTables( SimpleXMLElement $xmlSheet, Worksheet $docSheet, @@ -2319,6 +2358,7 @@ class Xlsx extends BaseReader array $dxfs ): void { if ($xmlSheet && $xmlSheet->tableParts) { + /** @var array{count: scalar} */ $attributes = $xmlSheet->tableParts->attributes() ?? ['count' => 0]; if (((int) $attributes['count']) > 0) { $this->readTablesInTablesFile($xmlSheet, $dir, $fileWorksheet, $zip, $docSheet, $namespaceTable, $tableStyles, $dxfs); @@ -2326,6 +2366,10 @@ class Xlsx extends BaseReader } } + /** + * @param TableDxfsStyle[] $tableStyles + * @param mixed[] $dxfs + */ private function readTablesInTablesFile( SimpleXMLElement $xmlSheet, string $dir, @@ -2361,11 +2405,14 @@ class Xlsx extends BaseReader } } + /** @return mixed[] */ private static function extractStyles(?SimpleXMLElement $sxml, string $node1, string $node2): array { $array = []; if ($sxml && $sxml->{$node1}->{$node2}) { - foreach ($sxml->{$node1}->{$node2} as $node) { + /** @var SimpleXMLElement */ + $temp = $sxml->{$node1}->{$node2}; + foreach ($temp as $node) { $array[] = $node; } } @@ -2373,6 +2420,7 @@ class Xlsx extends BaseReader return $array; } + /** @return string[] */ private static function extractPalette(?SimpleXMLElement $sxml): array { $array = []; @@ -2406,9 +2454,8 @@ class Xlsx extends BaseReader $firstRow = $matches[2]; $firstCol = $matches[1]; if (array_key_exists(3, $matches)) { - // https://github.com/phpstan/phpstan/issues/11602 - $lastCol = $matches[4]; // @phpstan-ignore-line - $lastRow = $matches[5]; // @phpstan-ignore-line + $lastCol = $matches[4]; + $lastRow = $matches[5]; } else { $lastCol = $firstCol; $lastRow = $firstRow; @@ -2416,6 +2463,7 @@ class Xlsx extends BaseReader ++$lastCol; for ($row = $firstRow; $row <= $lastRow; ++$row) { for ($col = $firstCol; $col !== $lastCol; ++$col) { + /** @var string $col */ if (!$cellCollection->has2("$col$row")) { continue; } diff --git a/src/PhpSpreadsheet/Reader/Xlsx/AutoFilter.php b/src/PhpSpreadsheet/Reader/Xlsx/AutoFilter.php index 49fe3609d..88a08318e 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/AutoFilter.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/AutoFilter.php @@ -51,6 +51,7 @@ class AutoFilter // Entries can be either filter elements foreach ($filterColumn->filters->filter as $filterRule) { // Operator is undefined, but always treated as EQUAL + /** @var SimpleXMLElement */ $attr2 = $filterRule->attributes() ?? ['val' => '']; $column->createRule()->setRule('', (string) $attr2['val'])->setRuleType(Rule::AUTOFILTER_RULETYPE_FILTER); } @@ -103,6 +104,7 @@ class AutoFilter $column->setJoin(Column::AUTOFILTER_COLUMN_JOIN_AND); } foreach ($customFilters->customFilter as $filterRule) { + /** @var SimpleXMLElement */ $attr2 = $filterRule->attributes() ?? ['operator' => '', 'val' => '']; $column->createRule()->setRule( (string) $attr2['operator'], diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php index beca090da..22233c76b 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php @@ -858,6 +858,7 @@ class Chart $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, 0, null, $marker, $fillColor, "$pointSize"); if (isset($seriesDetail->strRef->strCache)) { + /** @var array{formatCode: string, dataValues: mixed[]} */ $seriesData = $this->chartDataSeriesValues($seriesDetail->strRef->strCache->children($this->cNamespace), 's'); $seriesValues ->setFormatCode($seriesData['formatCode']) @@ -869,6 +870,7 @@ class Chart $seriesSource = (string) $seriesDetail->numRef->f; $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, $seriesSource, null, 0, null, $marker, $fillColor, "$pointSize"); if (isset($seriesDetail->numRef->numCache)) { + /** @var array{formatCode: string, dataValues: mixed[]} */ $seriesData = $this->chartDataSeriesValues($seriesDetail->numRef->numCache->children($this->cNamespace)); $seriesValues ->setFormatCode($seriesData['formatCode']) @@ -881,6 +883,7 @@ class Chart $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, 0, null, $marker, $fillColor, "$pointSize"); if (isset($seriesDetail->multiLvlStrRef->multiLvlStrCache)) { + /** @var array{formatCode: string, dataValues: mixed[]} */ $seriesData = $this->chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlStrRef->multiLvlStrCache->children($this->cNamespace), 's'); $seriesValues ->setFormatCode($seriesData['formatCode']) @@ -893,6 +896,7 @@ class Chart $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, 0, null, $marker, $fillColor, "$pointSize"); if (isset($seriesDetail->multiLvlNumRef->multiLvlNumCache)) { + /** @var array{formatCode: string, dataValues: mixed[]} */ $seriesData = $this->chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlNumRef->multiLvlNumCache->children($this->cNamespace), 's'); $seriesValues ->setFormatCode($seriesData['formatCode']) @@ -915,6 +919,7 @@ class Chart return null; } + /** @return mixed[] */ private function chartDataSeriesValues(SimpleXMLElement $seriesValueSet, string $dataType = 'n'): array { $seriesVal = []; @@ -953,6 +958,7 @@ class Chart ]; } + /** @return mixed[] */ private function chartDataSeriesValuesMultiLevel(SimpleXMLElement $seriesValueSet, string $dataType = 'n'): array { $seriesVal = []; @@ -1220,6 +1226,7 @@ class Chart return $font; } + /** @return mixed[] */ private function readChartAttributes(?SimpleXMLElement $chartDetail): array { $plotAttributes = []; @@ -1277,9 +1284,11 @@ class Chart return $plotAttributes; } + /** @param array $plotAttributes */ private function setChartAttributes(Layout $plotArea, array $plotAttributes): void { foreach ($plotAttributes as $plotAttributeKey => $plotAttributeValue) { + /** @var ?bool $plotAttributeValue */ switch ($plotAttributeKey) { case 'showLegendKey': $plotArea->setShowLegendKey($plotAttributeValue); @@ -1310,6 +1319,7 @@ class Chart break; case 'labelFont': + /** @var ?Font $plotAttributeValue */ $plotArea->setLabelFont($plotAttributeValue); break; @@ -1397,6 +1407,7 @@ class Chart 'innerShdw', ]; + /** @return array{type: ?string, value: ?string, alpha: ?int, brightness: ?int} */ private function readColor(SimpleXMLElement $colorXml): array { $result = [ diff --git a/src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php b/src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php index 63dd4ade5..b82b5558f 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php @@ -24,8 +24,7 @@ class ColumnAndRowAttributes extends BaseParserClass * Set Worksheet column attributes by attributes array passed. * * @param string $columnAddress A, B, ... DX, ... - * @param array $columnAttributes array of attributes (indexes are attribute name, values are value) - * 'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'width', ... ? + * @param array{xfIndex?: int, visible?: bool, collapsed?: bool, collapsed?: bool, outlineLevel?: int, rowHeight?: float, width?: int} $columnAttributes array of attributes (indexes are attribute name, values are value) */ private function setColumnAttributes(string $columnAddress, array $columnAttributes): void { @@ -50,7 +49,7 @@ class ColumnAndRowAttributes extends BaseParserClass * Set Worksheet row attributes by attributes array passed. * * @param int $rowNumber 1, 2, 3, ... 99, ... - * @param array $rowAttributes array of attributes (indexes are attribute name, values are value) + * @param array{xfIndex?: int, visible?: bool, collapsed?: bool, collapsed?: bool, outlineLevel?: int, rowHeight?: float} $rowAttributes array of attributes (indexes are attribute name, values are value) * 'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'rowHeight', ... ? */ private function setRowAttributes(int $rowNumber, array $rowAttributes): void @@ -99,6 +98,7 @@ class ColumnAndRowAttributes extends BaseParserClass || !$this->isFilteredColumn($readFilter, $columnCoordinate, $rowsAttributes) ) { if (!isset($columnsAttributesAreSet[$columnCoordinate])) { + /** @var array{xfIndex?: int, visible?: bool, collapsed?: bool, collapsed?: bool, outlineLevel?: int, rowHeight?: float, width?: int} $columnAttributes */ $this->setColumnAttributes($columnCoordinate, $columnAttributes); $columnsAttributesAreSet[$columnCoordinate] = true; } @@ -112,6 +112,7 @@ class ColumnAndRowAttributes extends BaseParserClass || !$this->isFilteredRow($readFilter, $rowCoordinate, $columnsAttributes) ) { if (!isset($rowsAttributesAreSet[$rowCoordinate])) { + /** @var array{xfIndex?: int, visible?: bool, collapsed?: bool, collapsed?: bool, outlineLevel?: int, rowHeight?: float} $rowAttributes */ $this->setRowAttributes($rowCoordinate, $rowAttributes); $rowsAttributesAreSet[$rowCoordinate] = true; } @@ -119,6 +120,7 @@ class ColumnAndRowAttributes extends BaseParserClass } } + /** @param mixed[] $rowsAttributes */ private function isFilteredColumn(IReadFilter $readFilter, string $columnCoordinate, array $rowsAttributes): bool { foreach ($rowsAttributes as $rowCoordinate => $rowAttributes) { @@ -130,6 +132,7 @@ class ColumnAndRowAttributes extends BaseParserClass return true; } + /** @return mixed[] */ private function readColumnAttributes(SimpleXMLElement $worksheetCols, bool $readDataOnly): array { $columnAttributes = []; @@ -153,6 +156,7 @@ class ColumnAndRowAttributes extends BaseParserClass return $columnAttributes; } + /** @return mixed[] */ private function readColumnRangeAttributes(?SimpleXMLElement $column, bool $readDataOnly): array { $columnAttributes = []; @@ -177,6 +181,7 @@ class ColumnAndRowAttributes extends BaseParserClass return $columnAttributes; } + /** @param mixed[] $columnsAttributes */ private function isFilteredRow(IReadFilter $readFilter, int $rowCoordinate, array $columnsAttributes): bool { foreach ($columnsAttributes as $columnCoordinate => $columnAttributes) { @@ -188,6 +193,7 @@ class ColumnAndRowAttributes extends BaseParserClass return false; } + /** @return mixed[] */ private function readRowAttributes(SimpleXMLElement $worksheetRow, bool $readDataOnly, bool $ignoreRowsWithNoCells, bool $readFilterIsNotNull): array { $rowAttributes = []; diff --git a/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php b/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php index 436d9ffb8..b09de2ad6 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php @@ -20,12 +20,15 @@ class ConditionalStyles private SimpleXMLElement $worksheetXml; + /** @var string[] */ private array $ns; + /** @var Style[] */ private array $dxfs; private StyleReader $styleReader; + /** @param Style[] $dxfs */ public function __construct(Worksheet $workSheet, SimpleXMLElement $worksheetXml, array $dxfs, StyleReader $styleReader) { $this->worksheet = $workSheet; @@ -59,6 +62,7 @@ class ConditionalStyles $this->worksheet->setSelectedCells($selectedCells); } + /** @param Conditional[][] $conditionals */ private function setConditionalsFromExt(array $conditionals): void { foreach ($conditionals as $conditionalRange => $cfRules) { @@ -70,6 +74,7 @@ class ConditionalStyles } } + /** @return array> */ private function readConditionalsFromExt(SimpleXMLElement $extLst): array { $conditionals = []; @@ -167,6 +172,7 @@ class ConditionalStyles return $cfStyle; } + /** @return mixed[] */ private function readConditionalStyles(SimpleXMLElement $xmlSheet): array { $conditionals = []; @@ -183,9 +189,11 @@ class ConditionalStyles return $conditionals; } + /** @param mixed[] $conditionals */ private function setConditionalStyles(Worksheet $worksheet, array $conditionals, SimpleXMLElement $xmlExtLst): void { foreach ($conditionals as $cellRangeReference => $cfRules) { + /** @var mixed[] $cfRules */ ksort($cfRules); // no longer needed for Xlsx, but helps Xls $conditionalStyles = $this->readStyleRules($cfRules, $xmlExtLst); @@ -204,8 +212,14 @@ class ConditionalStyles } } + /** + * @param mixed[] $cfRules + * + * @return Conditional[] + */ private function readStyleRules(array $cfRules, SimpleXMLElement $extLst): array { + /** @var ConditionalFormattingRuleExtension[] */ $conditionalFormattingRuleExtensions = ConditionalFormattingRuleExtension::parseExtLstXml($extLst); $conditionalStyles = []; @@ -261,6 +275,7 @@ class ConditionalStyles return $conditionalStyles; } + /** @param ConditionalFormattingRuleExtension[] $conditionalFormattingRuleExtensions */ private function readDataBarOfConditionalRule(SimpleXMLElement $cfRule, array $conditionalFormattingRuleExtensions): ConditionalDataBar { $dataBar = new ConditionalDataBar(); @@ -274,6 +289,7 @@ class ConditionalStyles $cfvoXml = $cfRule->dataBar->cfvo; $cfvoIndex = 0; foreach ((count($cfvoXml) > 1 ? $cfvoXml : [$cfvoXml]) as $cfvo) { //* @phpstan-ignore-line + /** @var SimpleXMLElement $cfvo */ if ($cfvoIndex === 0) { $dataBar->setMinimumConditionalFormatValueObject(new ConditionalFormatValueObject((string) $cfvo['type'], (string) $cfvo['val'])); } @@ -296,6 +312,7 @@ class ConditionalStyles private function readColorScale(SimpleXMLElement|stdClass $cfRule): ConditionalColorScale { $colorScale = new ConditionalColorScale(); + /** @var SimpleXMLElement $cfRule */ $count = count($cfRule->colorScale->cfvo); $idx = 0; foreach ($cfRule->colorScale->cfvo as $cfvoXml) { @@ -332,11 +349,13 @@ class ConditionalStyles return $colorScale; } + /** @param ConditionalFormattingRuleExtension[] $conditionalFormattingRuleExtensions */ private function readDataBarExtLstOfConditionalRule(ConditionalDataBar $dataBar, SimpleXMLElement $cfRule, array $conditionalFormattingRuleExtensions): void { if (isset($cfRule->extLst)) { $ns = $cfRule->extLst->getNamespaces(true); foreach ((count($cfRule->extLst) > 0 ? $cfRule->extLst->ext : [$cfRule->extLst->ext]) as $ext) { //* @phpstan-ignore-line + /** @var SimpleXMLElement $ext */ $extId = (string) $ext->children($ns['x14'])->id; if (isset($conditionalFormattingRuleExtensions[$extId]) && (string) $ext['uri'] === '{B025F937-C7B1-47D3-B67F-A62EFF666E3E}') { $dataBar->setConditionalFormattingRuleExt($conditionalFormattingRuleExtensions[$extId]); diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php b/src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php index 3eae5bb39..2c2d4af4b 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php @@ -11,6 +11,7 @@ class Hyperlinks { private Worksheet $worksheet; + /** @var string[] */ private array $hyperlinks = []; public function __construct(Worksheet $workSheet) @@ -44,7 +45,7 @@ class Hyperlinks foreach (Coordinate::extractAllCellReferencesInRange($attributes->ref) as $cellReference) { $cell = $worksheet->getCell($cellReference); if (isset($linkRel['id'])) { - $hyperlinkUrl = $this->hyperlinks[(string) $linkRel['id']] ?? null; + $hyperlinkUrl = $this->hyperlinks[(string) $linkRel['id']] ?? ''; if (isset($attributes['location'])) { $hyperlinkUrl .= '#' . (string) $attributes['location']; } diff --git a/src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php b/src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php index ca6ae0b09..766154e5b 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php @@ -18,6 +18,11 @@ class PageSetup extends BaseParserClass $this->worksheetXml = $worksheetXml; } + /** + * @param mixed[] $unparsedLoadedData + * + * @return mixed[] + */ public function load(array $unparsedLoadedData): array { $worksheetXml = $this->worksheetXml; @@ -46,6 +51,11 @@ class PageSetup extends BaseParserClass } } + /** + * @param mixed[] $unparsedLoadedData + * + * @return mixed[] + */ private function pageSetup(SimpleXMLElement $xmlSheet, Worksheet $worksheet, array $unparsedLoadedData): array { if ($xmlSheet->pageSetup) { @@ -82,6 +92,7 @@ class PageSetup extends BaseParserClass if (!str_ends_with($relid, 'ps')) { $relid .= 'ps'; } + /** @var mixed[][][] $unparsedLoadedData */ $unparsedLoadedData['sheets'][$worksheet->getCodeName()]['pageSetupRelId'] = $relid; } } diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Properties.php b/src/PhpSpreadsheet/Reader/Xlsx/Properties.php index 1a0517b19..a792235af 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Properties.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Properties.php @@ -79,7 +79,9 @@ class Properties $cellDataOfficeChildren = $xmlProperty->children('http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes'); $attributeType = $cellDataOfficeChildren->getName(); - $attributeValue = (string) $cellDataOfficeChildren->{$attributeType}; + /** @var SimpleXMLElement */ + $attributeValue = $cellDataOfficeChildren->{$attributeType}; + $attributeValue = (string) $attributeValue; $attributeValue = DocumentProperties::convertProperty($attributeValue, $attributeType); $attributeType = DocumentProperties::convertPropertyType($attributeType); $this->docProps->setCustomProperty($propertyName, $attributeValue, $attributeType); @@ -88,6 +90,7 @@ class Properties } } + /** @param null|false|scalar[] $array */ private function getArrayItem(null|array|false $array): string { return is_array($array) ? (string) ($array[0] ?? '') : ''; diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Styles.php b/src/PhpSpreadsheet/Reader/Xlsx/Styles.php index c1e27e9e3..5729add76 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Styles.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Styles.php @@ -23,10 +23,13 @@ class Styles extends BaseParserClass */ private ?Theme $theme = null; + /** @var mixed[] */ private array $workbookPalette = []; + /** @var mixed[] */ private array $styles = []; + /** @var array */ private array $cellStyles = []; private SimpleXMLElement $styleXml; @@ -38,6 +41,7 @@ class Styles extends BaseParserClass $this->namespace = $namespace; } + /** @param mixed[] $palette */ public function setWorkbookPalette(array $palette): void { $this->workbookPalette = $palette; @@ -63,6 +67,10 @@ class Styles extends BaseParserClass $this->theme = $theme; } + /** + * @param mixed[] $styles + * @param array $cellStyles + */ public function setStyleBaseData(?Theme $theme = null, array $styles = [], array $cellStyles = []): void { $this->theme = $theme; @@ -310,9 +318,12 @@ class Styles extends BaseParserClass if ($style instanceof SimpleXMLElement) { $this->readNumberFormat($docStyle->getNumberFormat(), $style->numFmt); } else { - $docStyle->getNumberFormat()->setFormatCode(self::formatGeneral((string) $style->numFmt)); + /** @var SimpleXMLElement */ + $temp = $style->numFmt; + $docStyle->getNumberFormat()->setFormatCode(self::formatGeneral((string) $temp)); } + /** @var SimpleXMLElement $style */ if (isset($style->font)) { $this->readFontStyle($docStyle->getFont(), $style->font); } @@ -416,6 +427,7 @@ class Styles extends BaseParserClass return ($background) ? 'FFFFFFFF' : 'FF000000'; } + /** @return mixed[] */ public function dxfs(bool $readDataOnly = false): array { $dxfs = []; @@ -448,7 +460,7 @@ class Styles extends BaseParserClass return $dxfs; } - // get TableStyles + /** @return TableDxfsStyle[] */ public function tableStyles(bool $readDataOnly = false): array { $tableStyles = []; @@ -488,6 +500,7 @@ class Styles extends BaseParserClass return $tableStyles; } + /** @return mixed[] */ public function styles(): array { return $this->styles; @@ -496,7 +509,7 @@ class Styles extends BaseParserClass /** * Get array item. * - * @param mixed $array (usually array, in theory can be false) + * @param false|mixed[] $array (usually array, in theory can be false) */ private static function getArrayItem(mixed $array): ?SimpleXMLElement { diff --git a/src/PhpSpreadsheet/Reader/Xlsx/TableReader.php b/src/PhpSpreadsheet/Reader/Xlsx/TableReader.php index c84b8198f..c82195866 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/TableReader.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/TableReader.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx; use PhpOffice\PhpSpreadsheet\Worksheet\Table; +use PhpOffice\PhpSpreadsheet\Worksheet\Table\TableDxfsStyle; use PhpOffice\PhpSpreadsheet\Worksheet\Table\TableStyle; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; use SimpleXMLElement; @@ -13,7 +14,7 @@ class TableReader private SimpleXMLElement $tableXml; - /** @var array|SimpleXMLElement */ + /** @var mixed[]|SimpleXMLElement */ private $tableAttributes; public function __construct(Worksheet $workSheet, SimpleXMLElement $tableXml) @@ -24,6 +25,9 @@ class TableReader /** * Loads Table into the Worksheet. + * + * @param TableDxfsStyle[] $tableStyles + * @param mixed[] $dxfs */ public function load(array $tableStyles, array $dxfs): void { @@ -37,13 +41,18 @@ class TableReader /** * Read Table from xml. + * + * @param TableDxfsStyle[] $tableStyles + * @param mixed[] $dxfs */ private function readTable(string $tableRange, array $tableStyles, array $dxfs): void { $table = new Table($tableRange); - $table->setName((string) ($this->tableAttributes['displayName'] ?? '')); - $table->setShowHeaderRow(((string) ($this->tableAttributes['headerRowCount'] ?? '')) !== '0'); - $table->setShowTotalsRow(((string) ($this->tableAttributes['totalsRowCount'] ?? '')) === '1'); + /** @var string[] */ + $attributes = $this->tableAttributes; + $table->setName((string) ($attributes['displayName'] ?? '')); + $table->setShowHeaderRow(((string) ($attributes['headerRowCount'] ?? '')) !== '0'); + $table->setShowTotalsRow(((string) ($attributes['totalsRowCount'] ?? '')) === '1'); $this->readTableAutoFilter($table, $this->tableXml->autoFilter); $this->readTableColumns($table, $this->tableXml->tableColumns); @@ -65,6 +74,7 @@ class TableReader } foreach ($autoFilterXml->filterColumn as $filterColumn) { + /** @var SimpleXMLElement */ $attributes = $filterColumn->attributes() ?? ['colId' => 0, 'hiddenButton' => 0]; $column = $table->getColumnByOffset((int) $attributes['colId']); $column->setShowFilterButton(((string) $attributes['hiddenButton']) !== '1'); @@ -78,6 +88,7 @@ class TableReader { $offset = 0; foreach ($tableColumnsXml->tableColumn as $tableColumn) { + /** @var SimpleXMLElement */ $attributes = $tableColumn->attributes() ?? ['totalsRowLabel' => 0, 'totalsRowFunction' => 0]; $column = $table->getColumnByOffset($offset++); @@ -99,6 +110,9 @@ class TableReader /** * Reads TableStyle from xml. + * + * @param TableDxfsStyle[] $tableStyles + * @param mixed[] $dxfs */ private function readTableStyle(Table $table, SimpleXMLElement $tableStyleInfoXml, array $tableStyles, array $dxfs): void { diff --git a/src/PhpSpreadsheet/Reader/Xlsx/WorkbookView.php b/src/PhpSpreadsheet/Reader/Xlsx/WorkbookView.php index f02de9a84..429efb089 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/WorkbookView.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/WorkbookView.php @@ -14,6 +14,7 @@ class WorkbookView $this->spreadsheet = $spreadsheet; } + /** @param array $mapSheetId */ public function viewSettings(SimpleXMLElement $xmlWorkbook, string $mainNS, array $mapSheetId, bool $readDataOnly): void { // Default active sheet index to the first loaded worksheet from the file diff --git a/src/PhpSpreadsheet/Shared/Escher/DgContainer/SpgrContainer.php b/src/PhpSpreadsheet/Shared/Escher/DgContainer/SpgrContainer.php index 84363ab20..04fb2234d 100644 --- a/src/PhpSpreadsheet/Shared/Escher/DgContainer/SpgrContainer.php +++ b/src/PhpSpreadsheet/Shared/Escher/DgContainer/SpgrContainer.php @@ -65,6 +65,7 @@ class SpgrContainer $allSpContainers[] = $child; } } + /** @var SpgrContainer\SpContainer[] $allSpContainers */ return $allSpContainers; } diff --git a/src/PhpSpreadsheet/Style/Font.php b/src/PhpSpreadsheet/Style/Font.php index 7d70dc4f7..89a099ee1 100644 --- a/src/PhpSpreadsheet/Style/Font.php +++ b/src/PhpSpreadsheet/Style/Font.php @@ -560,6 +560,7 @@ class Font extends Supervisor return $this->underlineColor; } + /** @param array{value: ?string, alpha: null|int|string, brightness?: null|int|string, type: ?string} $colorArray */ public function setUnderlineColor(array $colorArray): self { if (!$this->isSupervisor) { @@ -584,6 +585,7 @@ class Font extends Supervisor return $this->chartColor; } + /** @param array{value: ?string, alpha: null|int|string, brightness?: null|int|string, type: ?string} $colorArray */ public function setChartColor(array $colorArray): self { if (!$this->isSupervisor) { diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php index 9863f7223..33792a4da 100644 --- a/src/PhpSpreadsheet/Worksheet/Worksheet.php +++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -355,7 +355,7 @@ class Worksheet */ public function disconnectCells(): void { - if (isset($this->cellCollection)) { + if (isset($this->cellCollection)) { //* @phpstan-ignore-line $this->cellCollection->unsetWorksheetCells(); unset($this->cellCollection); } @@ -456,7 +456,7 @@ class Worksheet */ public function getCoordinates(bool $sorted = true): array { - if (!isset($this->cellCollection)) { + if (!isset($this->cellCollection)) { //* @phpstan-ignore-line return []; } @@ -2897,6 +2897,8 @@ class Worksheet * True - Return rows and columns indexed by their actual row and column IDs * @param bool $ignoreHidden False - Return values for rows/columns even if they are defined as hidden. * True - Don't return values for rows/columns that are defined as hidden. + * + * @return mixed[][] */ public function rangeToArray( string $range, @@ -3116,6 +3118,8 @@ class Worksheet * True - Return rows and columns indexed by their actual row and column IDs * @param bool $ignoreHidden False - Return values for rows/columns even if they are defined as hidden. * True - Don't return values for rows/columns that are defined as hidden. + * + * @return mixed[][] */ public function namedRangeToArray( string $definedName, @@ -3150,6 +3154,8 @@ class Worksheet * True - Return rows and columns indexed by their actual row and column IDs * @param bool $ignoreHidden False - Return values for rows/columns even if they are defined as hidden. * True - Don't return values for rows/columns that are defined as hidden. + * + * @return mixed[][] */ public function toArray( mixed $nullValue = null, diff --git a/src/PhpSpreadsheet/Writer/Html.php b/src/PhpSpreadsheet/Writer/Html.php index 4a85955c1..01a35f4d1 100644 --- a/src/PhpSpreadsheet/Writer/Html.php +++ b/src/PhpSpreadsheet/Writer/Html.php @@ -1330,7 +1330,7 @@ class Html extends BaseWriter return $html; } - /** @return array{null|''|Cell, array{}|non-falsy-string, non-empty-string} */ + /** @return array{null|''|Cell, array{}|string, non-empty-string} */ private function generateRowCellCss(Worksheet $worksheet, string $cellAddress, int $row, int $columnNumber): array { $cell = ($cellAddress > '') ? $worksheet->getCellCollection()->get($cellAddress) : ''; diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php index 176d96a50..b19339c9c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php @@ -107,13 +107,13 @@ class IndirectTest extends AllSetupTeardown { $reader = new ReaderXlsx(); $file = 'tests/data/Calculation/LookupRef/IndirectFormulaSelection.xlsx'; - $this->spreadsheet = $reader->load($file); - $sheet = $this->spreadsheet->getActiveSheet(); + $spreadsheet = $this->spreadsheet = $reader->load($file); + $sheet = $spreadsheet->getActiveSheet(); $result = $sheet->getCell('A5')->getCalculatedValue(); self::assertSame(100, $result); $value = $sheet->getCell('A5')->getValue(); self::assertSame('=CURRENCY_SELECTOR', $value); - $formula = $this->spreadsheet->getNamedFormula('CURRENCY_SELECTOR'); + $formula = $spreadsheet->getNamedFormula('CURRENCY_SELECTOR'); if ($formula === null) { self::fail('Expected named formula was not defined'); } else { diff --git a/tests/PhpSpreadsheetTests/Custom/ComplexAssert.php b/tests/PhpSpreadsheetTests/Custom/ComplexAssert.php index 45b734958..ddaf16d89 100644 --- a/tests/PhpSpreadsheetTests/Custom/ComplexAssert.php +++ b/tests/PhpSpreadsheetTests/Custom/ComplexAssert.php @@ -15,7 +15,8 @@ class ComplexAssert extends TestCase public function __construct() { - parent::__construct('complexAssert'); + // Phpstan doesn't want you to use "internal" method outside PHPunit namespace + parent::__construct('complexAssert'); //* @phpstan-ignore-line } private function testExpectedExceptions(string|float $expected, string|float $actual): bool diff --git a/tests/PhpSpreadsheetTests/Helper/SampleTest.php b/tests/PhpSpreadsheetTests/Helper/SampleTest.php index 3759ff17a..6020f1d91 100644 --- a/tests/PhpSpreadsheetTests/Helper/SampleTest.php +++ b/tests/PhpSpreadsheetTests/Helper/SampleTest.php @@ -31,6 +31,7 @@ class SampleTest extends TestCase // Unfortunately some tests are too long to run with code-coverage // analysis on GitHub Actions, so we need to exclude them + /** @var string[] */ global $argv; if (in_array('--coverage-clover', $argv)) { $tooLongToBeCovered = [ diff --git a/tests/PhpSpreadsheetTests/Helper/TextGridTest.php b/tests/PhpSpreadsheetTests/Helper/TextGridTest.php index 505e9198d..236326029 100644 --- a/tests/PhpSpreadsheetTests/Helper/TextGridTest.php +++ b/tests/PhpSpreadsheetTests/Helper/TextGridTest.php @@ -11,6 +11,7 @@ use PHPUnit\Framework\TestCase; class TextGridTest extends TestCase { + /** @param mixed[] $expected */ #[DataProvider('providerTextGrid')] public function testTextGrid( bool $cli, @@ -26,8 +27,10 @@ class TextGridTest extends TestCase ['="6"', '=TEXT(A2,"yyyy-mm-dd hh:mm")', null, '1<>2'], ['xyz', '=TEXT(A3,"yyyy-mm-dd hh:mm")'], ], strictNullComparison: true); + /** @var mixed[][] */ + $temp = $sheet->toArray(null, true, true, true); $textGrid = new TextGrid( - $sheet->toArray(null, true, true, true), + $temp, $cli, rowDividers: $rowDividers, rowHeaders: $rowHeaders, @@ -136,8 +139,10 @@ class TextGridTest extends TestCase [true, false], [true, true], ], strictNullComparison: true); + /** @var mixed[][] */ + $temp = $sheet->toArray(null, true, false, true); $textGrid = new TextGrid( - $sheet->toArray(null, true, false, true), + $temp, true, rowDividers: false, rowHeaders: false, diff --git a/tests/PhpSpreadsheetTests/Reader/Html/HtmlBorderTest.php b/tests/PhpSpreadsheetTests/Reader/Html/HtmlBorderTest.php index b516de04c..d3e86fe8c 100644 --- a/tests/PhpSpreadsheetTests/Reader/Html/HtmlBorderTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Html/HtmlBorderTest.php @@ -94,6 +94,7 @@ class HtmlBorderTest extends TestCase } $tests = $this->providerBorderStyle(); foreach ($tests as $test) { + /** @var array $test */ $covered[$test[0]] = 1; } foreach ($covered as $key => $val) { diff --git a/tests/PhpSpreadsheetTests/Reader/Xls/ConditionalFormattingBasicTest.php b/tests/PhpSpreadsheetTests/Reader/Xls/ConditionalFormattingBasicTest.php index ee39c7ce2..ead2d4a26 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xls/ConditionalFormattingBasicTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xls/ConditionalFormattingBasicTest.php @@ -7,11 +7,13 @@ namespace PhpOffice\PhpSpreadsheetTests\Reader\Xls; use PhpOffice\PhpSpreadsheet\Reader\Xls; use PhpOffice\PhpSpreadsheet\Style\Border; use PhpOffice\PhpSpreadsheet\Style\Conditional; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class ConditionalFormattingBasicTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DataProvider('conditionalFormattingProvider')] + /** @param mixed[][] $expectedRules */ + #[DataProvider('conditionalFormattingProvider')] public function testReadConditionalFormatting(string $expectedRange, array $expectedRules): void { $filename = 'tests/data/Reader/XLS/CF_Basic_Comparisons.xls'; diff --git a/tests/PhpSpreadsheetTests/Reader/Xls/ConditionalFormattingExpressionTest.php b/tests/PhpSpreadsheetTests/Reader/Xls/ConditionalFormattingExpressionTest.php index eb7a67916..62e319356 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xls/ConditionalFormattingExpressionTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xls/ConditionalFormattingExpressionTest.php @@ -6,11 +6,13 @@ namespace PhpOffice\PhpSpreadsheetTests\Reader\Xls; use PhpOffice\PhpSpreadsheet\Reader\Xls; use PhpOffice\PhpSpreadsheet\Style\Conditional; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class ConditionalFormattingExpressionTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DataProvider('conditionalFormattingProvider')] + /** @param mixed[][] $expectedRule */ + #[DataProvider('conditionalFormattingProvider')] public function testReadConditionalFormatting(string $expectedRange, array $expectedRule): void { $filename = 'tests/data/Reader/XLS/CF_Expression_Comparisons.xls'; diff --git a/tests/PhpSpreadsheetTests/Reader/Xls/DataValidationTest.php b/tests/PhpSpreadsheetTests/Reader/Xls/DataValidationTest.php index 3d30e8ab6..621d0890a 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xls/DataValidationTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xls/DataValidationTest.php @@ -6,11 +6,13 @@ namespace PhpOffice\PhpSpreadsheetTests\Reader\Xls; use PhpOffice\PhpSpreadsheet\Cell\DataValidation; use PhpOffice\PhpSpreadsheet\Reader\Xls; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class DataValidationTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DataProvider('dataValidationProvider')] + /** @param mixed[] $expectedRule */ + #[DataProvider('dataValidationProvider')] public function testDataValidation(string $expectedRange, array $expectedRule): void { $filename = 'tests/data/Reader/XLS/DataValidation.xls'; diff --git a/tests/PhpSpreadsheetTests/Reader/Xls/HiddenWorksheetTest.php b/tests/PhpSpreadsheetTests/Reader/Xls/HiddenWorksheetTest.php index 3a2949a51..b9aac4c7f 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xls/HiddenWorksheetTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xls/HiddenWorksheetTest.php @@ -38,6 +38,7 @@ class HiddenWorksheetTest extends TestCase $spreadsheet->disconnectWorksheets(); } + /** @return string[][] */ private function worksheetAssertions(): array { return [ diff --git a/tests/PhpSpreadsheetTests/Reader/Xls/LoadSheetsOnlyTest.php b/tests/PhpSpreadsheetTests/Reader/Xls/LoadSheetsOnlyTest.php index c8c543afd..2c8f50ecc 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xls/LoadSheetsOnlyTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xls/LoadSheetsOnlyTest.php @@ -30,9 +30,9 @@ class LoadSheetsOnlyTest extends TestCase //$reader->setLoadSheetsOnly(['Sheet1']); $names = $reader->listWorksheetNames($filename); $reader->setLoadSheetsOnly([$names[0]]); - $this->spreadsheet = $reader->load($filename); - self::assertSame(1, $this->spreadsheet->getSheetCount()); - self::assertSame('Sheet1', $this->spreadsheet->getActiveSheet()->getTitle()); + $spreadsheet = $this->spreadsheet = $reader->load($filename); + self::assertSame(1, $spreadsheet->getSheetCount()); + self::assertSame('Sheet1', $spreadsheet->getActiveSheet()->getTitle()); } public function testLoadSheet2Only(): void @@ -40,9 +40,9 @@ class LoadSheetsOnlyTest extends TestCase $filename = self::$testbook; $reader = new Xls(); $reader->setLoadSheetsOnly(['Sheet2']); - $this->spreadsheet = $reader->load($filename); - self::assertSame(1, $this->spreadsheet->getSheetCount()); - self::assertSame('Sheet2', $this->spreadsheet->getActiveSheet()->getTitle()); + $spreadsheet = $this->spreadsheet = $reader->load($filename); + self::assertSame(1, $spreadsheet->getSheetCount()); + self::assertSame('Sheet2', $spreadsheet->getActiveSheet()->getTitle()); } public function testLoadNoSheet(): void diff --git a/tests/PhpSpreadsheetTests/Reader/Xls/PageSetupTest.php b/tests/PhpSpreadsheetTests/Reader/Xls/PageSetupTest.php index 2eb2bc633..30f5b45ff 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xls/PageSetupTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xls/PageSetupTest.php @@ -73,6 +73,7 @@ class PageSetupTest extends TestCase $spreadsheet->disconnectWorksheets(); } + /** @return array */ private function pageSetupAssertions(): array { return [ @@ -108,6 +109,7 @@ class PageSetupTest extends TestCase ]; } + /** @return array */ private function pageMarginAssertions(): array { return [ diff --git a/tests/PhpSpreadsheetTests/Reader/Xls/PasswordTest.php b/tests/PhpSpreadsheetTests/Reader/Xls/PasswordTest.php new file mode 100644 index 000000000..bf5a62882 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xls/PasswordTest.php @@ -0,0 +1,55 @@ +load($filename); + $sheet = $spreadsheet->getActiveSheet(); + self::assertSame('x', $sheet->getCell('A1')->getValue()); + $spreadsheet->disconnectWorksheets(); + } + + public function testWrongPassword(): void + { + $this->expectException(ReaderException::class); + $this->expectExceptionMessage('Decryption password incorrect'); + $filename = 'tests/data/Reader/XLS/pwtest2.xls'; + $reader = new XlsReader(); + $spreadsheet = $reader->load($filename); + $sheet = $spreadsheet->getActiveSheet(); + self::assertSame('test2', $sheet->getCell('A1')->getValue()); + $spreadsheet->disconnectWorksheets(); + } + + public function testCorrectPassword(): void + { + $filename = 'tests/data/Reader/XLS/pwtest2.xls'; + $reader = new XlsReader(); + $reader->setEncryptionPassword('pwtest2'); + $spreadsheet = $reader->load($filename); + $sheet = $spreadsheet->getActiveSheet(); + self::assertSame('test2', $sheet->getCell('A1')->getValue()); + $spreadsheet->disconnectWorksheets(); + } + + public function testUnsupportedEncryption(): void + { + $this->expectException(ReaderException::class); + $this->expectExceptionMessage('Unsupported encryption algorithm'); + $filename = 'tests/data/Reader/XLS/pwtest3.xls'; + $reader = new XlsReader(); + $spreadsheet = $reader->load($filename); + $sheet = $spreadsheet->getActiveSheet(); + self::assertSame('test2', $sheet->getCell('A1')->getValue()); + $spreadsheet->disconnectWorksheets(); + } +} diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilter2Test.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilter2Test.php index e14c6a24a..1aa9fb7d0 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilter2Test.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilter2Test.php @@ -13,6 +13,7 @@ class AutoFilter2Test extends TestCase { private const TESTBOOK = 'tests/data/Reader/XLSX/autofilter2.xlsx'; + /** @return int[] */ public function getVisibleSheet(?Worksheet $sheet, int $maxRow): array { $actualVisible = []; diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilterEvaluateTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilterEvaluateTest.php index 70f332a16..25045bd8c 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilterEvaluateTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilterEvaluateTest.php @@ -12,6 +12,7 @@ use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional; class AutoFilterEvaluateTest extends AbstractFunctional { + /** @return int[] */ private function getVisibleSheet(Worksheet $sheet): array { $actualVisible = []; diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/CommentTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/CommentTest.php index 1eb9eca01..13e1996f2 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/CommentTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/CommentTest.php @@ -66,9 +66,12 @@ class CommentTest extends TestCase // Spreadsheet generated by Flexcel. Make sure we managed // to locate printerSettings since it used an unexpected link. - $pageSetupRel = $spreadsheet->getUnparsedLoadedData()['sheets']['Worksheet']['pageSetupRelId'] ?? ''; + /** @var mixed[][][][][] */ + $unparsedLoadedData = $spreadsheet->getUnparsedLoadedData(); + /** @var string */ + $pageSetupRel = $unparsedLoadedData['sheets']['Worksheet']['pageSetupRelId'] ?? ''; self::assertSame('flId1ps', $pageSetupRel); - $pageSetupPath = $spreadsheet->getUnparsedLoadedData()['sheets']['Worksheet']['printerSettings'][substr($pageSetupRel, 3)]['filePath'] ?? ''; + $pageSetupPath = $unparsedLoadedData['sheets']['Worksheet']['printerSettings'][substr($pageSetupRel, 3)]['filePath'] ?? ''; self::assertSame('xl/printerSettings/printerSettings1.bin', $pageSetupPath); $spreadsheet->disconnectWorksheets(); } diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/HiddenWorksheetTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/HiddenWorksheetTest.php index f6017a120..c7a3b8175 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/HiddenWorksheetTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/HiddenWorksheetTest.php @@ -35,6 +35,7 @@ class HiddenWorksheetTest extends TestCase $spreadsheet->disconnectWorksheets(); } + /** @return array */ private function worksheetAssertions(): array { return [ diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3126Test.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3126Test.php index 8a1d3d7d1..31a98d5a9 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3126Test.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3126Test.php @@ -22,9 +22,12 @@ class Issue3126Test extends TestCase self::assertCount(1, $gen1Images); $gen1hfName = array_key_exists('LF', $gen1Images) ? $gen1Images['LF']->getName() : ''; self::assertSame('fleche-verte-up-right', $gen1hfName); - $pageSetupRel = $generation1->getUnparsedLoadedData()['sheets']['Worksheet']['pageSetupRelId'] ?? ''; + /** @var mixed[][][][][] */ + $unparsedLoadedData = $generation1->getUnparsedLoadedData(); + /** @var string */ + $pageSetupRel = $unparsedLoadedData['sheets']['Worksheet']['pageSetupRelId'] ?? ''; self::assertSame('rId1ps', $pageSetupRel); - $pageSetupPath = $generation1->getUnparsedLoadedData()['sheets']['Worksheet']['printerSettings'][substr($pageSetupRel, 3)]['filePath'] ?? ''; + $pageSetupPath = $unparsedLoadedData['sheets']['Worksheet']['printerSettings'][substr($pageSetupRel, 3)]['filePath'] ?? ''; self::assertSame('xl/printerSettings/printerSettings1.bin', $pageSetupPath); $generation2Name = File::temporaryFilename(); @@ -39,9 +42,12 @@ class Issue3126Test extends TestCase self::assertCount(1, $gen2Images); $gen2hfName = array_key_exists('LF', $gen2Images) ? $gen2Images['LF']->getName() : ''; self::assertSame('fleche-verte-up-right', $gen2hfName); - $pageSetupRel = $generation2->getUnparsedLoadedData()['sheets']['Worksheet']['pageSetupRelId'] ?? ''; + /** @var mixed[][][][][] */ + $unparsedLoadedData = $generation2->getUnparsedLoadedData(); + /** @var string */ + $pageSetupRel = $unparsedLoadedData['sheets']['Worksheet']['pageSetupRelId'] ?? ''; self::assertSame('rId1ps', $pageSetupRel); - $pageSetupPath = $generation2->getUnparsedLoadedData()['sheets']['Worksheet']['printerSettings'][substr($pageSetupRel, 3)]['filePath'] ?? ''; + $pageSetupPath = $unparsedLoadedData['sheets']['Worksheet']['printerSettings'][substr($pageSetupRel, 3)]['filePath'] ?? ''; self::assertSame('xl/printerSettings/printerSettings1.bin', $pageSetupPath); $generation3Name = File::temporaryFilename(); @@ -56,9 +62,12 @@ class Issue3126Test extends TestCase self::assertCount(1, $gen3Images); $gen3hfName = array_key_exists('LF', $gen3Images) ? $gen3Images['LF']->getName() : ''; self::assertSame('fleche-verte-up-right', $gen3hfName); - $pageSetupRel = $generation3->getUnparsedLoadedData()['sheets']['Worksheet']['pageSetupRelId'] ?? ''; + /** @var mixed[][][][][] */ + $unparsedLoadedData = $generation3->getUnparsedLoadedData(); + /** @var string */ + $pageSetupRel = $unparsedLoadedData['sheets']['Worksheet']['pageSetupRelId'] ?? ''; self::assertSame('rId1ps', $pageSetupRel); - $pageSetupPath = $generation3->getUnparsedLoadedData()['sheets']['Worksheet']['printerSettings'][substr($pageSetupRel, 3)]['filePath'] ?? ''; + $pageSetupPath = $unparsedLoadedData['sheets']['Worksheet']['printerSettings'][substr($pageSetupRel, 3)]['filePath'] ?? ''; self::assertSame('xl/printerSettings/printerSettings1.bin', $pageSetupPath); unlink($generation2Name); diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3679ImgTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3679ImgTest.php index 5c9b38074..ad4937923 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3679ImgTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue3679ImgTest.php @@ -6,6 +6,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx; use PhpOffice\PhpSpreadsheet\Reader\Xlsx; use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional; +use SimpleXMLElement; class Issue3679ImgTest extends AbstractFunctional { @@ -23,6 +24,7 @@ class Issue3679ImgTest extends AbstractFunctional if ($drawings[0] === null) { self::fail('Unexpected null drawing'); } else { + /** @var SimpleXMLElement */ $srcRect = $drawings[0]->getSrcRect(); self::assertSame('448', (string) ($srcRect['r'] ?? '')); self::assertSame('65769', (string) ($srcRect['b'] ?? '')); diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/LoadSheetsOnlyTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/LoadSheetsOnlyTest.php index 5c70a7521..92f0cd53c 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/LoadSheetsOnlyTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/LoadSheetsOnlyTest.php @@ -30,9 +30,9 @@ class LoadSheetsOnlyTest extends TestCase //$reader->setLoadSheetsOnly(['Sheet1']); $names = $reader->listWorksheetNames($filename); $reader->setLoadSheetsOnly([$names[0]]); - $this->spreadsheet = $reader->load($filename); - self::assertSame(1, $this->spreadsheet->getSheetCount()); - self::assertSame('Sheet1', $this->spreadsheet->getActiveSheet()->getTitle()); + $spreadsheet = $this->spreadsheet = $reader->load($filename); + self::assertSame(1, $spreadsheet->getSheetCount()); + self::assertSame('Sheet1', $spreadsheet->getActiveSheet()->getTitle()); } public function testLoadSheet2Only(): void @@ -40,9 +40,9 @@ class LoadSheetsOnlyTest extends TestCase $filename = self::$testbook; $reader = new Xlsx(); $reader->setLoadSheetsOnly(['Sheet2']); - $this->spreadsheet = $reader->load($filename); - self::assertSame(1, $this->spreadsheet->getSheetCount()); - self::assertSame('Sheet2', $this->spreadsheet->getActiveSheet()->getTitle()); + $spreadsheet = $this->spreadsheet = $reader->load($filename); + self::assertSame(1, $spreadsheet->getSheetCount()); + self::assertSame('Sheet2', $spreadsheet->getActiveSheet()->getTitle()); } public function testLoadNoSheet(): void diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/PageSetupTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/PageSetupTest.php index 763dcfb07..bac85dbce 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/PageSetupTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/PageSetupTest.php @@ -67,6 +67,7 @@ class PageSetupTest extends TestCase $spreadsheet->disconnectWorksheets(); } + /** @return array */ private function pageSetupAssertions(): array { return [ @@ -102,6 +103,7 @@ class PageSetupTest extends TestCase ]; } + /** @return array */ private function pageMarginAssertions(): array { return [ diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/SheetProtectionTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/SheetProtectionTest.php index 123b39eb3..870f5bc8d 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/SheetProtectionTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/SheetProtectionTest.php @@ -43,6 +43,7 @@ class SheetProtectionTest extends AbstractFunctional $spreadsheet->disconnectWorksheets(); } + /** @return array */ private function pageSetupAssertions(): array { return [ diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/XlsxTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/XlsxTest.php index 7ce2ca7c1..bf8644f72 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/XlsxTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/XlsxTest.php @@ -166,7 +166,9 @@ class XlsxTest extends TestCase self::assertEquals(Conditional::CONDITION_CELLIS, $conditionalRule->getConditionType()); self::assertEquals(Conditional::OPERATOR_BETWEEN, $conditionalRule->getOperatorType()); self::assertEquals(['200', '400'], $conditionalRule->getConditions()); - self::assertSame('#,##0.00_-"€"', $conditionalRule->getStyle()->exportArray()['numberFormat']['formatCode']); + /** @var mixed[][] */ + $temp = $conditionalRule->getStyle()->exportArray(); + self::assertSame('#,##0.00_-"€"', $temp['numberFormat']['formatCode']); $spreadsheet->disconnectWorksheets(); } diff --git a/tests/PhpSpreadsheetTests/Shared/Date2Test.php b/tests/PhpSpreadsheetTests/Shared/Date2Test.php index c109e0279..97eea7933 100644 --- a/tests/PhpSpreadsheetTests/Shared/Date2Test.php +++ b/tests/PhpSpreadsheetTests/Shared/Date2Test.php @@ -8,6 +8,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalculationException; use PhpOffice\PhpSpreadsheet\Cell\Cell; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Style\NumberFormat; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class Date2Test extends TestCase @@ -37,24 +38,26 @@ class Date2Test extends TestCase Cell::setCalculateDateTimeType(-1); } - #[\PHPUnit\Framework\Attributes\DataProvider('providerTimeOnly')] + #[DataProvider('providerTimeOnly')] public function testTimeOnly(int|float $expectedResult, int|float|string $value, ?string $format = null): void { Cell::setCalculateDateTimeType(Cell::CALCULATE_TIME_FLOAT); - $this->spreadsheet = new Spreadsheet(); - self::assertSame(0, $this->spreadsheet->getActiveSheetIndex()); - $sheet = $this->spreadsheet->getActiveSheet(); - $newSheet = $this->spreadsheet->createSheet(); + $spreadsheet = $this->spreadsheet = new Spreadsheet(); + self::assertSame(0, $spreadsheet->getActiveSheetIndex()); + $sheet = $spreadsheet->getActiveSheet(); + $newSheet = $spreadsheet->createSheet(); $newSheet->getCell('B7')->setValue('Here'); $sheet->getCell('A1')->setValue($value); if ($format !== null) { - $sheet->getStyle('A1')->getNumberFormat()->setFormatCode($format); + $sheet->getStyle('A1') + ->getNumberFormat() + ->setFormatCode($format); } $sheet->setSelectedCells('B7'); - $this->spreadsheet->setActiveSheetIndex(1); + $spreadsheet->setActiveSheetIndex(1); self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); self::assertSame('B7', $sheet->getSelectedCells()); - self::assertSame(1, $this->spreadsheet->getActiveSheetIndex()); + self::assertSame(1, $spreadsheet->getActiveSheetIndex()); } public static function providerTimeOnly(): array @@ -80,24 +83,28 @@ class Date2Test extends TestCase ]; } - #[\PHPUnit\Framework\Attributes\DataProvider('providerDateAndTime')] + #[DataProvider('providerDateAndTime')] public function testDateAndTime(int|float $expectedResult, int|float|string $value, ?string $format = null): void { - Cell::setCalculateDateTimeType(Cell::CALCULATE_DATE_TIME_FLOAT); - $this->spreadsheet = new Spreadsheet(); - self::assertSame(0, $this->spreadsheet->getActiveSheetIndex()); - $sheet = $this->spreadsheet->getActiveSheet(); - $newSheet = $this->spreadsheet->createSheet(); + Cell::setCalculateDateTimeType( + Cell::CALCULATE_DATE_TIME_FLOAT + ); + $spreadsheet = $this->spreadsheet = new Spreadsheet(); + self::assertSame(0, $spreadsheet->getActiveSheetIndex()); + $sheet = $spreadsheet->getActiveSheet(); + $newSheet = $spreadsheet->createSheet(); $newSheet->getCell('B7')->setValue('Here'); $sheet->getCell('A1')->setValue($value); if ($format !== null) { - $sheet->getStyle('A1')->getNumberFormat()->setFormatCode($format); + $sheet->getStyle('A1') + ->getNumberFormat() + ->setFormatCode($format); } $sheet->setSelectedCells('B7'); - $this->spreadsheet->setActiveSheetIndex(1); + $spreadsheet->setActiveSheetIndex(1); self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); self::assertSame('B7', $sheet->getSelectedCells()); - self::assertSame(1, $this->spreadsheet->getActiveSheetIndex()); + self::assertSame(1, $spreadsheet->getActiveSheetIndex()); } public static function providerDateAndTime(): array @@ -123,44 +130,49 @@ class Date2Test extends TestCase ]; } - #[\PHPUnit\Framework\Attributes\DataProvider('providerAsis')] + #[DataProvider('providerAsis')] public function testDefault(int|float $expectedResult, int|float|string $value, ?string $format = null): void { - //Cell::setCalculateDateTimeType(Cell::CALCULATE_DATE_TIME_ASIS); - $this->spreadsheet = new Spreadsheet(); - self::assertSame(0, $this->spreadsheet->getActiveSheetIndex()); - $sheet = $this->spreadsheet->getActiveSheet(); - $newSheet = $this->spreadsheet->createSheet(); + $spreadsheet = $this->spreadsheet = new Spreadsheet(); + self::assertSame(0, $spreadsheet->getActiveSheetIndex()); + $sheet = $spreadsheet->getActiveSheet(); + $newSheet = $spreadsheet->createSheet(); $newSheet->getCell('B7')->setValue('Here'); $sheet->getCell('A1')->setValue($value); if ($format !== null) { - $sheet->getStyle('A1')->getNumberFormat()->setFormatCode($format); + $sheet->getStyle('A1') + ->getNumberFormat() + ->setFormatCode($format); } $sheet->setSelectedCells('B7'); - $this->spreadsheet->setActiveSheetIndex(1); + $spreadsheet->setActiveSheetIndex(1); self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); self::assertSame('B7', $sheet->getSelectedCells()); - self::assertSame(1, $this->spreadsheet->getActiveSheetIndex()); + self::assertSame(1, $spreadsheet->getActiveSheetIndex()); } - #[\PHPUnit\Framework\Attributes\DataProvider('providerAsis')] + #[DataProvider('providerAsis')] public function testAsis(int|float $expectedResult, int|float|string $value, ?string $format = null): void { - Cell::setCalculateDateTimeType(Cell::CALCULATE_DATE_TIME_ASIS); - $this->spreadsheet = new Spreadsheet(); - self::assertSame(0, $this->spreadsheet->getActiveSheetIndex()); - $sheet = $this->spreadsheet->getActiveSheet(); - $newSheet = $this->spreadsheet->createSheet(); + Cell::setCalculateDateTimeType( + Cell::CALCULATE_DATE_TIME_ASIS + ); + $spreadsheet = $this->spreadsheet = new Spreadsheet(); + self::assertSame(0, $spreadsheet->getActiveSheetIndex()); + $sheet = $spreadsheet->getActiveSheet(); + $newSheet = $spreadsheet->createSheet(); $newSheet->getCell('B7')->setValue('Here'); $sheet->getCell('A1')->setValue($value); if ($format !== null) { - $sheet->getStyle('A1')->getNumberFormat()->setFormatCode($format); + $sheet->getStyle('A1') + ->getNumberFormat() + ->setFormatCode($format); } $sheet->setSelectedCells('B7'); - $this->spreadsheet->setActiveSheetIndex(1); + $spreadsheet->setActiveSheetIndex(1); self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); self::assertSame('B7', $sheet->getSelectedCells()); - self::assertSame(1, $this->spreadsheet->getActiveSheetIndex()); + self::assertSame(1, $spreadsheet->getActiveSheetIndex()); } public static function providerAsis(): array diff --git a/tests/PhpSpreadsheetTests/Shared/StringHelperLocaleTest.php b/tests/PhpSpreadsheetTests/Shared/StringHelperLocaleTest.php index c4178f53a..d3c0b43df 100644 --- a/tests/PhpSpreadsheetTests/Shared/StringHelperLocaleTest.php +++ b/tests/PhpSpreadsheetTests/Shared/StringHelperLocaleTest.php @@ -32,12 +32,13 @@ class StringHelperLocaleTest extends TestCase public function testCurrency(): void { + $currentLocale = ($this->currentLocale === false) ? null : $this->currentLocale; if ($this->currentLocale === false || !setlocale(LC_ALL, 'de_DE.UTF-8', 'deu_deu.utf8')) { self::markTestSkipped('Unable to set German UTF8 locale for testing.'); } $result = StringHelper::getCurrencyCode(); self::assertSame('€', $result); - if (!setlocale(LC_ALL, $this->currentLocale)) { + if (!setlocale(LC_ALL, $currentLocale)) { self::markTestSkipped('Unable to restore default locale.'); } $result = StringHelper::getCurrencyCode(); diff --git a/tests/PhpSpreadsheetTests/SpreadsheetCopyCloneTest.php b/tests/PhpSpreadsheetTests/SpreadsheetCopyCloneTest.php index f45ed9385..1752230aa 100644 --- a/tests/PhpSpreadsheetTests/SpreadsheetCopyCloneTest.php +++ b/tests/PhpSpreadsheetTests/SpreadsheetCopyCloneTest.php @@ -29,8 +29,8 @@ class SpreadsheetCopyCloneTest extends TestCase #[DataProvider('providerCopyClone')] public function testCopyClone(string $type): void { - $this->spreadsheet = new Spreadsheet(); - $sheet = $this->spreadsheet->getActiveSheet(); + $spreadsheet = $this->spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); $sheet->setTitle('original'); $sheet->getStyle('A1')->getFont()->setName('font1'); $sheet->getStyle('A2')->getFont()->setName('font2'); @@ -45,14 +45,14 @@ class SpreadsheetCopyCloneTest extends TestCase self::assertSame('font1', $sheet->getStyle('A1')->getFont()->getName()); $sheet->setSelectedCells('A3'); if ($type === 'copy') { - $this->spreadsheet2 = $this->spreadsheet->copy(); + $spreadsheet2 = $this->spreadsheet2 = $spreadsheet->copy(); } else { - $this->spreadsheet2 = clone $this->spreadsheet; + $spreadsheet2 = $this->spreadsheet2 = clone $spreadsheet; } - self::assertSame($this->spreadsheet, $this->spreadsheet->getCalculationEngine()?->getSpreadsheet()); - self::assertSame($this->spreadsheet2, $this->spreadsheet2->getCalculationEngine()?->getSpreadsheet()); + self::assertSame($spreadsheet, $spreadsheet->getCalculationEngine()?->getSpreadsheet()); + self::assertSame($spreadsheet2, $spreadsheet2->getCalculationEngine()?->getSpreadsheet()); self::assertSame('A3', $sheet->getSelectedCells()); - $copysheet = $this->spreadsheet2->getActiveSheet(); + $copysheet = $spreadsheet2->getActiveSheet(); self::assertSame('A3', $copysheet->getSelectedCells()); self::assertSame('original', $copysheet->getTitle()); $copysheet->setTitle('unoriginal'); @@ -130,19 +130,19 @@ class SpreadsheetCopyCloneTest extends TestCase #[DataProvider('providerCopyClone2')] public function testCopyClone2(string $type, bool $suppress, bool $cache, bool $pruning, string $return): void { - $this->spreadsheet = new Spreadsheet(); - $calc = $this->spreadsheet->getCalculationEngine(); + $spreadsheet = $this->spreadsheet = new Spreadsheet(); + $calc = $spreadsheet->getCalculationEngine(); self::assertNotNull($calc); $calc->setSuppressFormulaErrors($suppress); $calc->setCalculationCacheEnabled($cache); $calc->setBranchPruningEnabled($pruning); $calc->setInstanceArrayReturnType($return); if ($type === 'copy') { - $this->spreadsheet2 = $this->spreadsheet->copy(); + $spreadsheet2 = $this->spreadsheet2 = $spreadsheet->copy(); } else { - $this->spreadsheet2 = clone $this->spreadsheet; + $spreadsheet2 = $this->spreadsheet2 = clone $spreadsheet; } - $calc2 = $this->spreadsheet2->getCalculationEngine(); + $calc2 = $spreadsheet2->getCalculationEngine(); self::assertNotNull($calc2); self::assertSame($suppress, $calc2->getSuppressFormulaErrors()); self::assertSame($cache, $calc2->getCalculationCacheEnabled()); diff --git a/tests/PhpSpreadsheetTests/SpreadsheetCoverageTest.php b/tests/PhpSpreadsheetTests/SpreadsheetCoverageTest.php index 3071e1297..338ddd60a 100644 --- a/tests/PhpSpreadsheetTests/SpreadsheetCoverageTest.php +++ b/tests/PhpSpreadsheetTests/SpreadsheetCoverageTest.php @@ -32,50 +32,50 @@ class SpreadsheetCoverageTest extends TestCase $properties = $this->spreadsheet->getProperties(); $properties->setCreator('Anyone'); $properties->setTitle('Description'); - $this->spreadsheet2 = new Spreadsheet(); + $spreadsheet2 = $this->spreadsheet2 = new Spreadsheet(); self::assertNotEquals($properties, $this->spreadsheet2->getProperties()); $properties2 = clone $properties; - $this->spreadsheet2->setProperties($properties2); - self::assertEquals($properties, $this->spreadsheet2->getProperties()); + $spreadsheet2->setProperties($properties2); + self::assertEquals($properties, $spreadsheet2->getProperties()); } public function testDocumentSecurity(): void { - $this->spreadsheet = new Spreadsheet(); - $security = $this->spreadsheet->getSecurity(); + $spreadsheet = $this->spreadsheet = new Spreadsheet(); + $security = $spreadsheet->getSecurity(); $security->setLockRevision(true); $revisionsPassword = 'revpasswd'; $security->setRevisionsPassword($revisionsPassword); - $this->spreadsheet2 = new Spreadsheet(); - self::assertNotEquals($security, $this->spreadsheet2->getSecurity()); + $spreadsheet2 = $this->spreadsheet2 = new Spreadsheet(); + self::assertNotEquals($security, $spreadsheet2->getSecurity()); $security2 = clone $security; - $this->spreadsheet2->setSecurity($security2); - self::assertEquals($security, $this->spreadsheet2->getSecurity()); + $spreadsheet2->setSecurity($security2); + self::assertEquals($security, $spreadsheet2->getSecurity()); } public function testCellXfCollection(): void { - $this->spreadsheet = new Spreadsheet(); - $sheet = $this->spreadsheet->getActiveSheet(); + $spreadsheet = $this->spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); $sheet->getStyle('A1')->getFont()->setName('font1'); $sheet->getStyle('A2')->getFont()->setName('font2'); $sheet->getStyle('A3')->getFont()->setName('font3'); $sheet->getStyle('B1')->getFont()->setName('font1'); $sheet->getStyle('B2')->getFont()->setName('font2'); - $collection = $this->spreadsheet->getCellXfCollection(); + $collection = $spreadsheet->getCellXfCollection(); self::assertCount(4, $collection); $font1Style = $collection[1]; - self::assertTrue($this->spreadsheet->cellXfExists($font1Style)); - self::assertSame('font1', $this->spreadsheet->getCellXfCollection()[1]->getFont()->getName()); + self::assertTrue($spreadsheet->cellXfExists($font1Style)); + self::assertSame('font1', $spreadsheet->getCellXfCollection()[1]->getFont()->getName()); self::assertSame('font1', $sheet->getStyle('A1')->getFont()->getName()); self::assertSame('font2', $sheet->getStyle('A2')->getFont()->getName()); self::assertSame('font3', $sheet->getStyle('A3')->getFont()->getName()); self::assertSame('font1', $sheet->getStyle('B1')->getFont()->getName()); self::assertSame('font2', $sheet->getStyle('B2')->getFont()->getName()); - $this->spreadsheet->removeCellXfByIndex(1); - self::assertFalse($this->spreadsheet->cellXfExists($font1Style)); - self::assertSame('font2', $this->spreadsheet->getCellXfCollection()[1]->getFont()->getName()); + $spreadsheet->removeCellXfByIndex(1); + self::assertFalse($spreadsheet->cellXfExists($font1Style)); + self::assertSame('font2', $spreadsheet->getCellXfCollection()[1]->getFont()->getName()); self::assertSame('Calibri', $sheet->getStyle('A1')->getFont()->getName()); self::assertSame('font2', $sheet->getStyle('A2')->getFont()->getName()); self::assertSame('font3', $sheet->getStyle('A3')->getFont()->getName()); @@ -109,14 +109,14 @@ class SpreadsheetCoverageTest extends TestCase public function testCellStyleXF(): void { - $this->spreadsheet = new Spreadsheet(); - $collection = $this->spreadsheet->getCellStyleXfCollection(); + $spreadsheet = $this->spreadsheet = new Spreadsheet(); + $collection = $spreadsheet->getCellStyleXfCollection(); self::assertCount(1, $collection); $styleXf = $collection[0]; - self::assertSame($styleXf, $this->spreadsheet->getCellStyleXfByIndex(0)); + self::assertSame($styleXf, $spreadsheet->getCellStyleXfByIndex(0)); $hash = $styleXf->getHashCode(); - self::assertSame($styleXf, $this->spreadsheet->getCellStyleXfByHashCode($hash)); - self::assertFalse($this->spreadsheet->getCellStyleXfByHashCode($hash . 'x')); + self::assertSame($styleXf, $spreadsheet->getCellStyleXfByHashCode($hash)); + self::assertFalse($spreadsheet->getCellStyleXfByHashCode($hash . 'x')); } public function testInvalidRemoveCellStyleXfByIndex(): void @@ -139,12 +139,13 @@ class SpreadsheetCoverageTest extends TestCase { $this->expectException(SSException::class); $this->expectExceptionMessage('Invalid visibility value.'); - $this->spreadsheet = new Spreadsheet(); - $this->spreadsheet->setVisibility(Spreadsheet::VISIBILITY_HIDDEN); - self::assertSame(Spreadsheet::VISIBILITY_HIDDEN, $this->spreadsheet->getVisibility()); - $this->spreadsheet->setVisibility(null); - self::assertSame(Spreadsheet::VISIBILITY_VISIBLE, $this->spreadsheet->getVisibility()); - $this->spreadsheet->setVisibility('badvalue'); + $spreadsheet = $this->spreadsheet = new Spreadsheet(); + $spreadsheet + ->setVisibility(Spreadsheet::VISIBILITY_HIDDEN); + self::assertSame(Spreadsheet::VISIBILITY_HIDDEN, $spreadsheet->getVisibility()); + $spreadsheet->setVisibility(null); + self::assertSame(Spreadsheet::VISIBILITY_VISIBLE, $spreadsheet->getVisibility()); + $spreadsheet->setVisibility('badvalue'); } public function testInvalidTabRatio(): void diff --git a/tests/PhpSpreadsheetTests/SpreadsheetDuplicateSheetTest.php b/tests/PhpSpreadsheetTests/SpreadsheetDuplicateSheetTest.php index b84026700..f7b033233 100644 --- a/tests/PhpSpreadsheetTests/SpreadsheetDuplicateSheetTest.php +++ b/tests/PhpSpreadsheetTests/SpreadsheetDuplicateSheetTest.php @@ -21,7 +21,7 @@ class SpreadsheetDuplicateSheetTest extends TestCase public function testDuplicate(): void { - $this->spreadsheet = new Spreadsheet(); + $spreadsheet = $this->spreadsheet = new Spreadsheet(); $sheet = $this->spreadsheet->getActiveSheet(); $sheet->setTitle('original'); $sheet->getCell('A1')->setValue('text1'); @@ -50,7 +50,7 @@ class SpreadsheetDuplicateSheetTest extends TestCase $newSheet->getStyle('A2')->getFont()->getBold() ); $sheetNames = []; - foreach ($this->spreadsheet->getWorksheetIterator() as $worksheet) { + foreach ($spreadsheet->getWorksheetIterator() as $worksheet) { $sheetNames[] = $worksheet->getTitle(); } $expected = ['original', 'original 1', 'added', 'added 1']; diff --git a/tests/PhpSpreadsheetTests/Style/FontTest.php b/tests/PhpSpreadsheetTests/Style/FontTest.php index 20df75b1a..389454527 100644 --- a/tests/PhpSpreadsheetTests/Style/FontTest.php +++ b/tests/PhpSpreadsheetTests/Style/FontTest.php @@ -102,6 +102,7 @@ class FontTest extends TestCase [ 'type' => 'srgbClr', 'value' => 'FF0000', + 'alpha' => null, ] ); $font2bHash = $font2->getHashCode(); diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/CalculationErrorTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/CalculationErrorTest.php index 8a22768ff..1bb4fc0c9 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/CalculationErrorTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/CalculationErrorTest.php @@ -29,18 +29,18 @@ class CalculationErrorTest extends AbstractFunctional public function testCalculationExceptionSuppressed(): void { - $this->spreadsheet = new Spreadsheet(); + $spreadsheet = $this->spreadsheet = new Spreadsheet(); $sheet = $this->spreadsheet->getActiveSheet(); - $calculation = Calculation::getInstance($this->spreadsheet); + $calculation = Calculation::getInstance($spreadsheet); self::assertFalse($calculation->getSuppressFormulaErrors()); $calculation->setSuppressFormulaErrors(true); $sheet->getCell('A1')->setValue('=SUM('); $sheet->getCell('A2')->setValue('=2+3'); - $this->reloadedSpreadsheet = $this->writeAndReload($this->spreadsheet, 'Xlsx'); + $spreadsheet2 = $this->reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx'); $rcalculation = Calculation::getInstance($this->reloadedSpreadsheet); self::assertFalse($rcalculation->getSuppressFormulaErrors()); $rcalculation->setSuppressFormulaErrors(true); - $rsheet = $this->reloadedSpreadsheet->getActiveSheet(); + $rsheet = $spreadsheet2->getActiveSheet(); self::assertSame('=SUM(', $rsheet->getCell('A1')->getValue()); self::assertFalse($rsheet->getCell('A1')->getCalculatedValue()); self::assertSame('=2+3', $rsheet->getCell('A2')->getValue()); @@ -53,12 +53,12 @@ class CalculationErrorTest extends AbstractFunctional { $this->expectException(CalcException::class); $this->expectExceptionMessage("Formula Error: Expecting ')'"); - $this->spreadsheet = new Spreadsheet(); - $sheet = $this->spreadsheet->getActiveSheet(); - $calculation = Calculation::getInstance($this->spreadsheet); + $spreadsheet = $this->spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $calculation = Calculation::getInstance($spreadsheet); self::assertFalse($calculation->getSuppressFormulaErrors()); $sheet->getCell('A1')->setValue('=SUM('); $sheet->getCell('A2')->setValue('=2+3'); - $this->reloadedSpreadsheet = $this->writeAndReload($this->spreadsheet, 'Xlsx'); + $this->reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx'); } } diff --git a/tests/data/Reader/XLS/pwtest.xls b/tests/data/Reader/XLS/pwtest.xls new file mode 100644 index 000000000..a82e0f6fe Binary files /dev/null and b/tests/data/Reader/XLS/pwtest.xls differ diff --git a/tests/data/Reader/XLS/pwtest2.xls b/tests/data/Reader/XLS/pwtest2.xls new file mode 100644 index 000000000..76b4bd342 Binary files /dev/null and b/tests/data/Reader/XLS/pwtest2.xls differ diff --git a/tests/data/Reader/XLS/pwtest3.xls b/tests/data/Reader/XLS/pwtest3.xls new file mode 100644 index 000000000..1038052c2 Binary files /dev/null and b/tests/data/Reader/XLS/pwtest3.xls differ