Skip to content

Commit e35b39a

Browse files
authored
Merge pull request #3482 from PHPOffice/Xlsx-Reader_Windows-Folder-Separator-in-Zip
Handle zips with Windoze directory separators (`\`) rather than the standard linux (`/`)
2 parents 00c34e7 + b48232c commit e35b39a

File tree

5 files changed

+95
-5
lines changed

5 files changed

+95
-5
lines changed

src/PhpSpreadsheet/Reader/Xlsx.php

+10-3
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ public function listWorksheetInfo($filename)
252252
$xmlWorkbook = $this->loadZip($relTarget, $mainNS);
253253
if ($xmlWorkbook->sheets) {
254254
$dir = dirname($relTarget);
255+
255256
/** @var SimpleXMLElement $eleSheet */
256257
foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
257258
$tmpInfo = [
@@ -267,8 +268,8 @@ public function listWorksheetInfo($filename)
267268

268269
$xml = new XMLReader();
269270
$xml->xml(
270-
$this->getSecurityScannerOrThrow()->scanFile(
271-
'zip://' . File::realpath($filename) . '#' . $fileWorksheetPath
271+
$this->getSecurityScannerOrThrow()->scan(
272+
$this->getFromZipArchive($this->zip, $fileWorksheetPath)
272273
),
273274
null,
274275
Settings::getLibXmlLoaderOptions()
@@ -403,12 +404,18 @@ private function getFromZipArchive(ZipArchive $archive, $fileName = '')
403404
// Sadly, some 3rd party xlsx generators don't use consistent case for filenaming
404405
// so we need to load case-insensitively from the zip file
405406

406-
// Apache POI fixes
407407
$contents = $archive->getFromName($fileName, 0, ZipArchive::FL_NOCASE);
408+
409+
// Apache POI fixes
408410
if ($contents === false) {
409411
$contents = $archive->getFromName(substr($fileName, 1), 0, ZipArchive::FL_NOCASE);
410412
}
411413

414+
// Has the file been saved with Windoze directory separators rather than unix?
415+
if ($contents === false) {
416+
$contents = $archive->getFromName(str_replace('/', '\\', $fileName), 0, ZipArchive::FL_NOCASE);
417+
}
418+
412419
return ($contents === false) ? '' : $contents;
413420
}
414421

src/PhpSpreadsheet/Shared/File.php

+14-2
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,11 @@ public static function assertFile(string $filename, string $zipMember = ''): voi
156156
if ($zipMember !== '') {
157157
$zipfile = "zip://$filename#$zipMember";
158158
if (!self::fileExists($zipfile)) {
159-
throw new ReaderException("Could not find zip member $zipfile");
159+
// Has the file been saved with Windoze directory separators rather than unix?
160+
$zipfile = "zip://$filename#" . str_replace('/', '\\', $zipMember);
161+
if (!self::fileExists($zipfile)) {
162+
throw new ReaderException("Could not find zip member $zipfile");
163+
}
160164
}
161165
}
162166
}
@@ -180,6 +184,14 @@ public static function testFileNoThrow(string $filename, ?string $zipMember = nu
180184
return self::validateZipFirst4($filename);
181185
}
182186

183-
return self::fileExists("zip://$filename#$zipMember");
187+
$zipfile = "zip://$filename#$zipMember";
188+
if (self::fileExists($zipfile)) {
189+
return true;
190+
}
191+
192+
// Has the file been saved with Windoze directory separators rather than unix?
193+
$zipfile = "zip://$filename#" . str_replace('/', '\\', $zipMember);
194+
195+
return self::fileExists($zipfile);
184196
}
185197
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
4+
5+
use PhpOffice\PhpSpreadsheet\IOFactory;
6+
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
7+
use PHPUnit\Framework\TestCase;
8+
9+
class DirectorySeparatorTest extends TestCase
10+
{
11+
/**
12+
* @dataProvider providerDirectorySeparator
13+
*/
14+
public function testDirectorySeparatorIdentify(string $fileName): void
15+
{
16+
$filename = "tests/data/Reader/XLSX/{$fileName}";
17+
$reader = IOFactory::identify($filename);
18+
19+
self::assertSame('Xlsx', $reader);
20+
}
21+
22+
/**
23+
* @dataProvider providerDirectorySeparator
24+
*/
25+
public function testDirectorySeparatorWorksheetNames(string $fileName): void
26+
{
27+
$filename = "tests/data/Reader/XLSX/{$fileName}";
28+
$reader = new Xlsx();
29+
$sheetList = $reader->listWorksheetNames($filename);
30+
31+
self::assertCount(1, $sheetList);
32+
self::assertSame('Sheet', $sheetList[0]);
33+
}
34+
35+
/**
36+
* @dataProvider providerDirectorySeparator
37+
*/
38+
public function testDirectorySeparatorWorksheetInfo(string $fileName): void
39+
{
40+
$filename = "tests/data/Reader/XLSX/{$fileName}";
41+
$reader = new Xlsx();
42+
$sheetData = $reader->listWorksheetInfo($filename);
43+
44+
self::assertCount(1, $sheetData);
45+
self::assertSame('Sheet', $sheetData[0]['worksheetName']);
46+
self::assertSame(3, (int) $sheetData[0]['totalRows']);
47+
self::assertSame(21, (int) $sheetData[0]['totalColumns']);
48+
}
49+
50+
/**
51+
* @dataProvider providerDirectorySeparator
52+
*/
53+
public function testDirectorySeparatorLoad(string $fileName): void
54+
{
55+
$filename = "tests/data/Reader/XLSX/{$fileName}";
56+
$reader = new Xlsx();
57+
$spreadsheet = $reader->load($filename);
58+
59+
$cellValue = $spreadsheet->getActiveSheet()->getCell('A1')->getValue();
60+
61+
self::assertSame('Key ID', $cellValue);
62+
}
63+
64+
public function providerDirectorySeparator(): array
65+
{
66+
return [
67+
['Zip-Linux-Directory-Separator.xlsx'],
68+
['Zip-Windows-Directory-Separator.xlsx'],
69+
];
70+
}
71+
}
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)