Skip to content
This repository has been archived by the owner on May 26, 2022. It is now read-only.

Commit

Permalink
Merge pull request #126 from box/fix_xmlreader_open_issue_windows
Browse files Browse the repository at this point in the history
Fix "Cannot open file" issue with XMLReader::open on Windows
  • Loading branch information
adrilo committed Oct 15, 2015
2 parents 4598019 + 01cc8b3 commit d1c4d56
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 13 deletions.
38 changes: 37 additions & 1 deletion src/Spout/Common/Helper/GlobalFunctionsHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,43 @@ public function file_exists($fileName)
*/
public function file_get_contents($filePath)
{
return file_get_contents($filePath);
$realFilePath = $this->convertToUseRealPath($filePath);
return file_get_contents($realFilePath);
}

/**
* Updates the given file path to use a real path.
* This is to avoid issues on some Windows setup.
*
* @param string $filePath File path
* @return string The file path using a real path
*/
protected function convertToUseRealPath($filePath)
{
$realFilePath = $filePath;

if ($this->isZipStream($filePath)) {
if (preg_match('/zip:\/\/(.*)#(.*)/', $filePath, $matches)) {
$documentPath = $matches[1];
$documentInsideZipPath = $matches[2];
$realFilePath = 'zip://' . realpath($documentPath) . '#' . $documentInsideZipPath;
}
} else {
$realFilePath = realpath($filePath);
}

return $realFilePath;
}

/**
* Returns whether the given path is a zip stream.
*
* @param string $path Path pointing to a document
* @return bool TRUE if path is a zip stream, FALSE otherwise
*/
protected function isZipStream($path)
{
return (strpos($path, 'zip://') === 0);
}

/**
Expand Down
4 changes: 3 additions & 1 deletion src/Spout/Reader/AbstractReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ public function open($filePath)
}

try {
$this->openReader($filePath);
// Need to use realpath to fix "Can't open file" on some Windows setup
$fileRealPath = realpath($filePath);
$this->openReader($fileRealPath);
$this->isStreamOpened = true;
} catch (\Exception $exception) {
throw new IOException("Could not open $filePath for reading! ({$exception->getMessage()})");
Expand Down
33 changes: 29 additions & 4 deletions src/Spout/Reader/Wrapper/XMLReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,45 @@ class XMLReader extends \XMLReader
public function open($URI, $encoding = null, $options = 0)
{
$wasOpenSuccessful = false;
$realPathURI = $this->convertURIToUseRealPath($URI);

// HHVM does not check if file exists within zip file
// @link https://github.com/facebook/hhvm/issues/5779
if ($this->isRunningHHVM() && $this->isZipStream($URI)) {
if ($this->fileExistsWithinZip($URI)) {
$wasOpenSuccessful = parent::open($URI, $encoding, $options|LIBXML_NONET);
if ($this->isRunningHHVM() && $this->isZipStream($realPathURI)) {
if ($this->fileExistsWithinZip($realPathURI)) {
$wasOpenSuccessful = parent::open($realPathURI, $encoding, $options|LIBXML_NONET);
}
} else {
$wasOpenSuccessful = parent::open($URI, $encoding, $options|LIBXML_NONET);
$wasOpenSuccessful = parent::open($realPathURI, $encoding, $options|LIBXML_NONET);
}

return $wasOpenSuccessful;
}

/**
* Updates the given URI to use a real path.
* This is to avoid issues on some Windows setup.
*
* @param string $URI URI
* @return string The URI using a real path
*/
protected function convertURIToUseRealPath($URI)
{
$realPathURI = $URI;

if ($this->isZipStream($URI)) {
if (preg_match('/zip:\/\/(.*)#(.*)/', $URI, $matches)) {
$documentPath = $matches[1];
$documentInsideZipPath = $matches[2];
$realPathURI = 'zip://' . realpath($documentPath) . '#' . $documentInsideZipPath;
}
} else {
$realPathURI = realpath($URI);
}

return $realPathURI;
}

/**
* Returns whether the given URI is a zip stream.
*
Expand Down
35 changes: 35 additions & 0 deletions tests/Spout/Reader/Wrapper/XMLReaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,39 @@ public function testFileExistsWithinZip($innerFilePath, $expectedResult)

$this->assertEquals($expectedResult, $isZipStream);
}

/**
* @return array
*/
public function dataProviderForTestConvertURIToUseRealPath()
{
$tempFolder = realpath(sys_get_temp_dir());

return [
['/../../../' . $tempFolder . '/test.xlsx', $tempFolder . '/test.xlsx'],
[$tempFolder . '/test.xlsx', $tempFolder . '/test.xlsx'],
['zip://' . $tempFolder . '/test.xlsx#test.xml', 'zip://' . $tempFolder . '/test.xlsx#test.xml'],
['zip:///../../../' . $tempFolder . '/test.xlsx#test.xml', 'zip://' . $tempFolder . '/test.xlsx#test.xml'],
];
}

/**
* @dataProvider dataProviderForTestConvertURIToUseRealPath
*
* @param string $URI
* @param string $expectedConvertedURI
* @return void
*/
public function testConvertURIToUseRealPath($URI, $expectedConvertedURI)
{
$tempFolder = sys_get_temp_dir();
touch($tempFolder . '/test.xlsx');

$xmlReader = new XMLReader();
$convertedURI = \ReflectionHelper::callMethodOnObject($xmlReader, 'convertURIToUseRealPath', $URI);

$this->assertEquals($expectedConvertedURI, $convertedURI);

unlink($tempFolder . '/test.xlsx');
}
}
14 changes: 7 additions & 7 deletions tests/Spout/TestUsingResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
trait TestUsingResource {

/** @var string Path to the test resources folder */
private $resourcesPath = 'tests/resources/';
private $resourcesPath = 'tests/resources';

/** @var string Path to the test generated resources folder */
private $generatedResourcesPath = 'tests/resources/generated/';
private $generatedResourcesPath = 'tests/resources/generated';

/** @var string Path to the test resources folder, that does not have writing permissions */
private $generatedUnwritableResourcesPath = 'tests/resources/generated/unwritable/';
private $generatedUnwritableResourcesPath = 'tests/resources/generated/unwritable';

/**
* @param string $resourceName
Expand All @@ -25,7 +25,7 @@ trait TestUsingResource {
protected function getResourcePath($resourceName)
{
$resourceType = pathinfo($resourceName, PATHINFO_EXTENSION);
$resourcePath = $this->resourcesPath . strtolower($resourceType) . '/' . $resourceName;
$resourcePath = realpath($this->resourcesPath) . '/' . strtolower($resourceType) . '/' . $resourceName;

return (file_exists($resourcePath) ? $resourcePath : null);
}
Expand All @@ -37,7 +37,7 @@ protected function getResourcePath($resourceName)
protected function getGeneratedResourcePath($resourceName)
{
$resourceType = pathinfo($resourceName, PATHINFO_EXTENSION);
$generatedResourcePath = $this->generatedResourcesPath . strtolower($resourceType) . '/' . $resourceName;
$generatedResourcePath = realpath($this->generatedResourcesPath) . '/' . strtolower($resourceType) . '/' . $resourceName;

return $generatedResourcePath;
}
Expand All @@ -49,7 +49,7 @@ protected function getGeneratedResourcePath($resourceName)
protected function createGeneratedFolderIfNeeded($resourceName)
{
$resourceType = pathinfo($resourceName, PATHINFO_EXTENSION);
$generatedResourcePathForType = $this->generatedResourcesPath . strtolower($resourceType);
$generatedResourcePathForType = $this->generatedResourcesPath . '/' . strtolower($resourceType);

if (!file_exists($generatedResourcePathForType)) {
mkdir($generatedResourcePathForType, 0777, true);
Expand All @@ -62,7 +62,7 @@ protected function createGeneratedFolderIfNeeded($resourceName)
*/
protected function getGeneratedUnwritableResourcePath($resourceName)
{
return $this->generatedUnwritableResourcesPath . $resourceName;
return realpath($this->generatedUnwritableResourcesPath) . '/' . $resourceName;
}

/**
Expand Down

0 comments on commit d1c4d56

Please sign in to comment.