Fix "Cannot open file" issue with XMLReader::open on Windows
This occurred when using relative paths. Using realpath() solves this issue.
This commit is contained in:
parent
45980195cd
commit
01cc8b3da0
@ -164,7 +164,43 @@ class GlobalFunctionsHelper
|
|||||||
*/
|
*/
|
||||||
public function file_get_contents($filePath)
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,7 +72,9 @@ abstract class AbstractReader implements ReaderInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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;
|
$this->isStreamOpened = true;
|
||||||
} catch (\Exception $exception) {
|
} catch (\Exception $exception) {
|
||||||
throw new IOException("Could not open $filePath for reading! ({$exception->getMessage()})");
|
throw new IOException("Could not open $filePath for reading! ({$exception->getMessage()})");
|
||||||
|
@ -26,20 +26,45 @@ class XMLReader extends \XMLReader
|
|||||||
public function open($URI, $encoding = null, $options = 0)
|
public function open($URI, $encoding = null, $options = 0)
|
||||||
{
|
{
|
||||||
$wasOpenSuccessful = false;
|
$wasOpenSuccessful = false;
|
||||||
|
$realPathURI = $this->convertURIToUseRealPath($URI);
|
||||||
|
|
||||||
// HHVM does not check if file exists within zip file
|
// HHVM does not check if file exists within zip file
|
||||||
// @link https://github.com/facebook/hhvm/issues/5779
|
// @link https://github.com/facebook/hhvm/issues/5779
|
||||||
if ($this->isRunningHHVM() && $this->isZipStream($URI)) {
|
if ($this->isRunningHHVM() && $this->isZipStream($realPathURI)) {
|
||||||
if ($this->fileExistsWithinZip($URI)) {
|
if ($this->fileExistsWithinZip($realPathURI)) {
|
||||||
$wasOpenSuccessful = parent::open($URI, $encoding, $options|LIBXML_NONET);
|
$wasOpenSuccessful = parent::open($realPathURI, $encoding, $options|LIBXML_NONET);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$wasOpenSuccessful = parent::open($URI, $encoding, $options|LIBXML_NONET);
|
$wasOpenSuccessful = parent::open($realPathURI, $encoding, $options|LIBXML_NONET);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $wasOpenSuccessful;
|
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.
|
* Returns whether the given URI is a zip stream.
|
||||||
*
|
*
|
||||||
|
@ -163,4 +163,39 @@ class XMLReaderTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$this->assertEquals($expectedResult, $isZipStream);
|
$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');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,13 +10,13 @@ namespace Box\Spout;
|
|||||||
trait TestUsingResource {
|
trait TestUsingResource {
|
||||||
|
|
||||||
/** @var string Path to the test resources folder */
|
/** @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 */
|
/** @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 */
|
/** @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
|
* @param string $resourceName
|
||||||
@ -25,7 +25,7 @@ trait TestUsingResource {
|
|||||||
protected function getResourcePath($resourceName)
|
protected function getResourcePath($resourceName)
|
||||||
{
|
{
|
||||||
$resourceType = pathinfo($resourceName, PATHINFO_EXTENSION);
|
$resourceType = pathinfo($resourceName, PATHINFO_EXTENSION);
|
||||||
$resourcePath = $this->resourcesPath . strtolower($resourceType) . '/' . $resourceName;
|
$resourcePath = realpath($this->resourcesPath) . '/' . strtolower($resourceType) . '/' . $resourceName;
|
||||||
|
|
||||||
return (file_exists($resourcePath) ? $resourcePath : null);
|
return (file_exists($resourcePath) ? $resourcePath : null);
|
||||||
}
|
}
|
||||||
@ -37,7 +37,7 @@ trait TestUsingResource {
|
|||||||
protected function getGeneratedResourcePath($resourceName)
|
protected function getGeneratedResourcePath($resourceName)
|
||||||
{
|
{
|
||||||
$resourceType = pathinfo($resourceName, PATHINFO_EXTENSION);
|
$resourceType = pathinfo($resourceName, PATHINFO_EXTENSION);
|
||||||
$generatedResourcePath = $this->generatedResourcesPath . strtolower($resourceType) . '/' . $resourceName;
|
$generatedResourcePath = realpath($this->generatedResourcesPath) . '/' . strtolower($resourceType) . '/' . $resourceName;
|
||||||
|
|
||||||
return $generatedResourcePath;
|
return $generatedResourcePath;
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ trait TestUsingResource {
|
|||||||
protected function createGeneratedFolderIfNeeded($resourceName)
|
protected function createGeneratedFolderIfNeeded($resourceName)
|
||||||
{
|
{
|
||||||
$resourceType = pathinfo($resourceName, PATHINFO_EXTENSION);
|
$resourceType = pathinfo($resourceName, PATHINFO_EXTENSION);
|
||||||
$generatedResourcePathForType = $this->generatedResourcesPath . strtolower($resourceType);
|
$generatedResourcePathForType = $this->generatedResourcesPath . '/' . strtolower($resourceType);
|
||||||
|
|
||||||
if (!file_exists($generatedResourcePathForType)) {
|
if (!file_exists($generatedResourcePathForType)) {
|
||||||
mkdir($generatedResourcePathForType, 0777, true);
|
mkdir($generatedResourcePathForType, 0777, true);
|
||||||
@ -62,7 +62,7 @@ trait TestUsingResource {
|
|||||||
*/
|
*/
|
||||||
protected function getGeneratedUnwritableResourcePath($resourceName)
|
protected function getGeneratedUnwritableResourcePath($resourceName)
|
||||||
{
|
{
|
||||||
return $this->generatedUnwritableResourcesPath . $resourceName;
|
return realpath($this->generatedUnwritableResourcesPath) . '/' . $resourceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user