Skip to content

Commit 492479e

Browse files
author
Bill Schaller
committed
Merge pull request #126 from doctrine/hotfix/#113-testing-windows-file-path-length-limitations-1-5
Hotfix/#113 testing windows file path length limitations Backport #122
2 parents 04bd73d + 3197628 commit 492479e

File tree

3 files changed

+85
-3
lines changed

3 files changed

+85
-3
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ services:
2424
before_install:
2525
- if [[ $TRAVIS_PHP_VERSION != 'hhvm' && $TRAVIS_PHP_VERSION != '7.0' ]]; then pecl install riak-beta; fi;
2626
- if [[ $TRAVIS_PHP_VERSION =~ 5.[34] ]] ; then echo 'extension="apc.so"' >> ./tests/travis/php.ini; fi;
27-
- if [[ $TRAVIS_PHP_VERSION =~ 5.[56] ]] ; then echo yes | pecl install apcu; fi;
27+
- if [[ $TRAVIS_PHP_VERSION =~ 5.[56] ]] ; then echo yes | pecl install apcu-4.0.10; fi;
2828
- if [[ $TRAVIS_PHP_VERSION = 7.* ]] ; then pecl config-set preferred_state beta; echo yes | pecl install apcu; fi;
2929
- if [[ $TRAVIS_PHP_VERSION != 'hhvm' ]]; then phpenv config-add ./tests/travis/php.ini; fi;
3030

lib/Doctrine/Common/Cache/FileCache.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ protected function getFilename($id)
137137
if (
138138
'' === $id
139139
|| ((strlen($id) * 2 + $this->extensionStringLength) > 255)
140-
|| (($this->isRunningOnWindows && $this->directoryStringLength + 4 + strlen($id) * 2 + $this->extensionStringLength) > 259)
140+
|| ($this->isRunningOnWindows && ($this->directoryStringLength + 4 + strlen($id) * 2 + $this->extensionStringLength) > 259)
141141
) {
142142
// Most filesystems have a limit of 255 chars for each path component. On Windows the the whole path is limited
143143
// to 260 chars (including terminating null char). Using long UNC ("\\?\" prefix) does not work with the PHP API.

tests/Doctrine/Tests/Common/Cache/FileCacheTest.php

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public function testNonIntUmaskThrowsInvalidArgumentException()
9191

9292
$this->getMock(
9393
'Doctrine\Common\Cache\FileCache',
94-
array(),
94+
array('doFetch', 'doContains', 'doSave'),
9595
array('', '', 'invalid')
9696
);
9797
}
@@ -129,4 +129,86 @@ public function testGetExtensionReturnsExtensionString()
129129

130130
$this->assertEquals($extension, $actualExtension);
131131
}
132+
133+
/**
134+
* @runInSeparateProcess
135+
*
136+
* @covers \Doctrine\Common\Cache\FileCache::getFilename
137+
*/
138+
public function testWindowsPathLengthLimitationsAreCorrectlyRespected()
139+
{
140+
if (! defined('PHP_WINDOWS_VERSION_BUILD')) {
141+
define('PHP_WINDOWS_VERSION_BUILD', 'Yes, this is the "usual suspect", with the usual limitations');
142+
}
143+
144+
// Not using __DIR__ because it can get screwed up when xdebug debugger is attached.
145+
$basePath = realpath(sys_get_temp_dir());
146+
147+
// If the base path length is even, pad it with '/aa' so it's odd.
148+
// That way we can test a path of length 260
149+
// 260 characters is too large - null terminator is included in allowable length
150+
if (!(strlen($basePath) % 1)) {
151+
$basePath .= DIRECTORY_SEPARATOR . "aa";
152+
}
153+
154+
$fileCache = $this->getMockForAbstractClass(
155+
'Doctrine\Common\Cache\FileCache',
156+
array($basePath, '.doctrine.cache')
157+
);
158+
159+
$baseDirLength = strlen($basePath);
160+
$extensionLength = strlen('.doctrine.cache');
161+
$windowsPathMaxLength = 259; // 260 bytes including null terminator
162+
$maxKeyLength = $windowsPathMaxLength - ($baseDirLength + $extensionLength);
163+
164+
self::assertSame('61', bin2hex('a'), '(added just for clarity and system integrity check)');
165+
166+
$tooLongKey = str_repeat('a', ($maxKeyLength / 2) - 1); // note: 1 char because reasons, ok?
167+
$fittingKey = str_repeat('a', ($maxKeyLength / 2) - 2); // note: 2 chars due to path separator added as well
168+
169+
$tooLongKeyHash = hash('sha256', $tooLongKey);
170+
$fittingKeyHash = hash('sha256', $fittingKey);
171+
172+
$getFileName = new \ReflectionMethod($fileCache, 'getFilename');
173+
174+
$getFileName->setAccessible(true);
175+
176+
$this->assertEquals(
177+
$windowsPathMaxLength + 1,
178+
strlen($basePath
179+
. DIRECTORY_SEPARATOR
180+
. substr($tooLongKeyHash, 0, 2)
181+
. DIRECTORY_SEPARATOR
182+
. bin2hex($tooLongKey)
183+
. '.doctrine.cache'),
184+
sprintf('Key expected to be too long is %d characters long', $windowsPathMaxLength + 1)
185+
);
186+
187+
$this->assertSame(
188+
$basePath . DIRECTORY_SEPARATOR . substr($tooLongKeyHash, 0, 2) . DIRECTORY_SEPARATOR . '_' . $tooLongKeyHash . '.doctrine.cache',
189+
$getFileName->invoke($fileCache, $tooLongKey),
190+
'Keys over the limit of the allowed length are hashed correctly'
191+
);
192+
193+
$this->assertLessThan(
194+
$windowsPathMaxLength,
195+
strlen($basePath
196+
. DIRECTORY_SEPARATOR
197+
. substr($fittingKeyHash, 0, 2)
198+
. DIRECTORY_SEPARATOR
199+
. bin2hex($fittingKey)
200+
. '.doctrine.cache'),
201+
sprintf(
202+
'Key expected to fit the length limit(%d) is less than %d characters long',
203+
$windowsPathMaxLength,
204+
$windowsPathMaxLength
205+
)
206+
);
207+
208+
$this->assertSame(
209+
$basePath . DIRECTORY_SEPARATOR . substr($fittingKeyHash, 0, 2) . DIRECTORY_SEPARATOR . bin2hex($fittingKey) . '.doctrine.cache',
210+
$getFileName->invoke($fileCache, $fittingKey),
211+
'Keys below limit of the allowed length are used directly, unhashed'
212+
);
213+
}
132214
}

0 commit comments

Comments
 (0)