• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PHPOffice / PhpSpreadsheet / 17307529777

28 Aug 2025 08:46PM UTC coverage: 95.112%. Remained the same
17307529777

Pull #4618

github

web-flow
Merge 2fd3ac555 into b79b77cf0
Pull Request #4618: Option to Create Blank Sheet If LoadSheetsOnly Doesn't Find Any

23 of 24 new or added lines in 6 files covered. (95.83%)

40185 of 42250 relevant lines covered (95.11%)

346.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.65
/src/PhpSpreadsheet/Reader/BaseReader.php
1
<?php
2

3
namespace PhpOffice\PhpSpreadsheet\Reader;
4

5
use PhpOffice\PhpSpreadsheet\Cell\IValueBinder;
6
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
7
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
8
use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
9
use PhpOffice\PhpSpreadsheet\Shared\File;
10
use PhpOffice\PhpSpreadsheet\Spreadsheet;
11

12
abstract class BaseReader implements IReader
13
{
14
    /**
15
     * Read data only?
16
     * Identifies whether the Reader should only read data values for cells, and ignore any formatting information;
17
     *        or whether it should read both data and formatting.
18
     */
19
    protected bool $readDataOnly = false;
20

21
    /**
22
     * Read empty cells?
23
     * Identifies whether the Reader should read data values for all cells, or should ignore cells containing
24
     *         null value or empty string.
25
     */
26
    protected bool $readEmptyCells = true;
27

28
    /**
29
     * Read charts that are defined in the workbook?
30
     * Identifies whether the Reader should read the definitions for any charts that exist in the workbook;.
31
     */
32
    protected bool $includeCharts = false;
33

34
    /**
35
     * Restrict which sheets should be loaded?
36
     * This property holds an array of worksheet names to be loaded. If null, then all worksheets will be loaded.
37
     * This property is ignored for Csv, Html, and Slk.
38
     *
39
     * @var null|string[]
40
     */
41
    protected ?array $loadSheetsOnly = null;
42

43
    /**
44
     * Ignore rows with no cells?
45
     * Identifies whether the Reader should ignore rows with no cells.
46
     *        Currently implemented only for Xlsx.
47
     */
48
    protected bool $ignoreRowsWithNoCells = false;
49

50
    /**
51
     * Allow external images. Use with caution.
52
     * Improper specification of these within a spreadsheet
53
     * can subject the caller to security exploits.
54
     */
55
    protected bool $allowExternalImages = false;
56

57
    /**
58
     * Create a blank sheet if none are read,
59
     * possibly due to a typo when using LoadSheetsOnly.
60
     */
61
    protected bool $createBlankSheetIfNoneRead = false;
62

63
    /**
64
     * IReadFilter instance.
65
     */
66
    protected IReadFilter $readFilter;
67

68
    /** @var resource */
69
    protected $fileHandle;
70

71
    protected ?XmlScanner $securityScanner = null;
72

73
    protected ?IValueBinder $valueBinder = null;
74

75
    public function __construct()
76
    {
77
        $this->readFilter = new DefaultReadFilter();
1,772✔
78
    }
79

80
    public function getReadDataOnly(): bool
81
    {
82
        return $this->readDataOnly;
1✔
83
    }
84

85
    public function setReadDataOnly(bool $readCellValuesOnly): self
86
    {
87
        $this->readDataOnly = $readCellValuesOnly;
10✔
88

89
        return $this;
10✔
90
    }
91

92
    public function getReadEmptyCells(): bool
93
    {
94
        return $this->readEmptyCells;
2✔
95
    }
96

97
    public function setReadEmptyCells(bool $readEmptyCells): self
98
    {
99
        $this->readEmptyCells = $readEmptyCells;
7✔
100

101
        return $this;
7✔
102
    }
103

104
    public function getIgnoreRowsWithNoCells(): bool
105
    {
106
        return $this->ignoreRowsWithNoCells;
1✔
107
    }
108

109
    public function setIgnoreRowsWithNoCells(bool $ignoreRowsWithNoCells): self
110
    {
111
        $this->ignoreRowsWithNoCells = $ignoreRowsWithNoCells;
1✔
112

113
        return $this;
1✔
114
    }
115

116
    public function getIncludeCharts(): bool
117
    {
118
        return $this->includeCharts;
2✔
119
    }
120

121
    public function setIncludeCharts(bool $includeCharts): self
122
    {
123
        $this->includeCharts = $includeCharts;
70✔
124

125
        return $this;
70✔
126
    }
127

128
    /** @return null|string[] */
129
    public function getLoadSheetsOnly(): ?array
130
    {
131
        return $this->loadSheetsOnly;
2✔
132
    }
133

134
    /** @param null|string|string[] $sheetList */
135
    public function setLoadSheetsOnly(string|array|null $sheetList): self
136
    {
137
        if ($sheetList === null) {
35✔
138
            return $this->setLoadAllSheets();
1✔
139
        }
140

141
        $this->loadSheetsOnly = is_array($sheetList) ? $sheetList : [$sheetList];
34✔
142

143
        return $this;
34✔
144
    }
145

146
    public function setLoadAllSheets(): self
147
    {
148
        $this->loadSheetsOnly = null;
4✔
149

150
        return $this;
4✔
151
    }
152

153
    public function getReadFilter(): IReadFilter
154
    {
155
        return $this->readFilter;
928✔
156
    }
157

158
    public function setReadFilter(IReadFilter $readFilter): self
159
    {
160
        $this->readFilter = $readFilter;
15✔
161

162
        return $this;
15✔
163
    }
164

165
    /**
166
     * Allow external images. Use with caution.
167
     * Improper specification of these within a spreadsheet
168
     * can subject the caller to security exploits.
169
     */
170
    public function setAllowExternalImages(bool $allowExternalImages): self
171
    {
172
        $this->allowExternalImages = $allowExternalImages;
8✔
173

174
        return $this;
8✔
175
    }
176

177
    public function getAllowExternalImages(): bool
178
    {
179
        return $this->allowExternalImages;
2✔
180
    }
181

182
    /**
183
     * Create a blank sheet if none are read,
184
     * possibly due to a typo when using LoadSheetsOnly.
185
     */
186
    public function setCreateBlankSheetIfNoneRead(bool $createBlankSheetIfNoneRead): self
187
    {
188
        $this->createBlankSheetIfNoneRead = $createBlankSheetIfNoneRead;
5✔
189

190
        return $this;
5✔
191
    }
192

193
    public function getSecurityScanner(): ?XmlScanner
194
    {
195
        return $this->securityScanner;
2✔
196
    }
197

198
    public function getSecurityScannerOrThrow(): XmlScanner
199
    {
200
        if ($this->securityScanner === null) {
1,422✔
201
            throw new ReaderException('Security scanner is unexpectedly null');
1✔
202
        }
203

204
        return $this->securityScanner;
1,421✔
205
    }
206

207
    protected function processFlags(int $flags): void
208
    {
209
        if (((bool) ($flags & self::LOAD_WITH_CHARTS)) === true) {
1,575✔
210
            $this->setIncludeCharts(true);
2✔
211
        }
212
        if (((bool) ($flags & self::READ_DATA_ONLY)) === true) {
1,575✔
213
            $this->setReadDataOnly(true);
2✔
214
        }
215
        if (((bool) ($flags & self::IGNORE_EMPTY_CELLS)) === true) {
1,575✔
216
            $this->setReadEmptyCells(false);
×
217
        }
218
        if (((bool) ($flags & self::IGNORE_ROWS_WITH_NO_CELLS)) === true) {
1,575✔
219
            $this->setIgnoreRowsWithNoCells(true);
1✔
220
        }
221
        if (((bool) ($flags & self::ALLOW_EXTERNAL_IMAGES)) === true) {
1,575✔
222
            $this->setAllowExternalImages(true);
×
223
        }
224
        if (((bool) ($flags & self::DONT_ALLOW_EXTERNAL_IMAGES)) === true) {
1,575✔
225
            $this->setAllowExternalImages(false);
×
226
        }
227
        if (((bool) ($flags & self::CREATE_BLANK_SHEET_IF_NONE_READ)) === true) {
1,575✔
NEW
228
            $this->setCreateBlankSheetIfNoneRead(true);
×
229
        }
230
    }
231

232
    protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
233
    {
234
        throw new PhpSpreadsheetException('Reader classes must implement their own loadSpreadsheetFromFile() method');
1✔
235
    }
236

237
    /**
238
     * Loads Spreadsheet from file.
239
     *
240
     * @param int $flags the optional second parameter flags may be used to identify specific elements
241
     *                       that should be loaded, but which won't be loaded by default, using these values:
242
     *                            IReader::LOAD_WITH_CHARTS - Include any charts that are defined in the loaded file
243
     */
244
    public function load(string $filename, int $flags = 0): Spreadsheet
245
    {
246
        $this->processFlags($flags);
1,575✔
247

248
        try {
249
            return $this->loadSpreadsheetFromFile($filename);
1,575✔
250
        } catch (ReaderException $e) {
49✔
251
            throw $e;
30✔
252
        }
253
    }
254

255
    /**
256
     * Open file for reading.
257
     */
258
    protected function openFile(string $filename): void
259
    {
260
        $fileHandle = false;
659✔
261
        if ($filename) {
659✔
262
            File::assertFile($filename);
656✔
263

264
            // Open file
265
            $fileHandle = fopen($filename, 'rb');
653✔
266
        }
267
        if ($fileHandle === false) {
656✔
268
            throw new ReaderException('Could not open file ' . $filename . ' for reading.');
3✔
269
        }
270

271
        $this->fileHandle = $fileHandle;
653✔
272
    }
273

274
    /**
275
     * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns).
276
     *
277
     * @return array<int, array{worksheetName: string, lastColumnLetter: string, lastColumnIndex: int, totalRows: int, totalColumns: int, sheetState: string}>
278
     */
279
    public function listWorksheetInfo(string $filename): array
280
    {
281
        throw new PhpSpreadsheetException('Reader classes must implement their own listWorksheetInfo() method');
1✔
282
    }
283

284
    /**
285
     * Returns names of the worksheets from a file,
286
     * possibly without parsing the whole file to a Spreadsheet object.
287
     * Readers will often have a more efficient method with which
288
     * they can override this method.
289
     *
290
     * @return string[]
291
     */
292
    public function listWorksheetNames(string $filename): array
293
    {
294
        $returnArray = [];
11✔
295
        $info = $this->listWorksheetInfo($filename);
11✔
296
        foreach ($info as $infoArray) {
11✔
297
            $returnArray[] = $infoArray['worksheetName'];
11✔
298
        }
299

300
        return $returnArray;
11✔
301
    }
302

303
    public function getValueBinder(): ?IValueBinder
304
    {
305
        return $this->valueBinder;
×
306
    }
307

308
    public function setValueBinder(?IValueBinder $valueBinder): self
309
    {
310
        $this->valueBinder = $valueBinder;
6✔
311

312
        return $this;
6✔
313
    }
314

315
    protected function newSpreadsheet(): Spreadsheet
316
    {
317
        return new Spreadsheet();
1,610✔
318
    }
319
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc