8000 Windows and Intl fixes · symfony/symfony@ea5d656 · GitHub
[go: up one dir, main page]

Skip to content

Commit ea5d656

Browse files
Windows and Intl fixes
1 parent 8bbd8d9 commit ea5d656

File tree

21 files changed

+229
-132
lines changed

21 files changed

+229
-132
lines changed

src/Symfony/Component/Console/Tests/ApplicationTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,10 @@ public function testRenderException()
491491

492492
public function testRenderExceptionWithDoubleWidthCharacters()
493493
{
494+
if (!function_exists('mb_strwidth')) {
495+
$this->markTestSkipped('The "mb_strwidth" function is not available');
496+
}
497+
494498
$application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth'));
495499
$application->setAutoExit(false);
496500
$application->expects($this->any())

src/Symfony/Component/DomCrawler/Crawler.php

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -156,20 +156,43 @@ public function addHtmlContent($content, $charset = 'UTF-8')
156156
$dom = new \DOMDocument('1.0', $charset);
157157
$dom->validateOnParse = true;
158158

159-
if (function_exists('mb_convert_encoding')) {
160-
$hasError = false;
161-
set_error_handler(function () use (&$hasError) {
162-
$hasError = true;
163-
});
164-
$tmpContent = @mb_convert_encoding($content, 'HTML-ENTITIES', $charset);
165-
166-
restore_error_handler();
167-
168-
if (!$hasError) {
169-
$content = $tmpContent;
159+
set_error_handler(function () {throw new \Exception();});
160+
161+
try {
162+
// Convert charset to HTML-entities to work around bugs in DOMDocument::loadHTML()
163+
164+
if (function_exists('mb_convert_encoding')) {
165+
$content = mb_convert_encoding($content, 'HTML-ENTITIES', $charset);
166+
} elseif (function_exists('iconv')) {
167+
$content = preg_replace_callback(
168+
'/[\x80-\xFF]+/',
169+
function ($m) {
170+
$m = unpack('C*', $m[0]);
171+
$i = 1;
172+
$entities = '';
173+
174+
while (isset($m[$i])) {
175+
if (0xF0 <= $m[$i]) {
176+
$c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
177+
} elseif (0xE0 <= $m[$i]) {
178+
$c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
179+
} else {
180+
$c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
181+
}
182+
183+
$entities .= '&#'.$c.';';
184+
}
185+
186+
return $entities;
187+
},
188+
iconv($charset, 'UTF-8', $content)
189+
);
170190
}
191+
} catch (\Exception $e) {
171192
}
172193

194+
restore_error_handler();
195+
173196
if ('' !== trim($content)) {
174197
@$dom->loadHTML($content);
175198
}

src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ public function testAddHtmlContent()
8080

8181
/**
8282
* @covers Symfony\Component\DomCrawler\Crawler::addHtmlContent
83+
* @requires extension mbstring
8384
*/
8485
public function testAddHtmlContentCharset()
8586
{
@@ -114,6 +115,7 @@ public function testAddHtmlContentUnsupportedCharset()
114115

115116
/**
116117
* @covers Symfony\Component\DomCrawler\Crawler::addHtmlContent
118+
* @requires extension mbstring
117119
*/
118120
public function testAddHtmlContentCharsetGbk()
119121
{
@@ -234,7 +236,7 @@ public function testAddContent()
234236
$this->assertEquals('中文', $crawler->filterXPath('//span')->text(), '->addContent() guess wrong charset');
235237

236238
$crawler = new Crawler();
237-
$crawler->addContent(mb_convert_encoding('<html><head><meta charset="Shift_JIS"></head><body>日本語</body></html>', 'SJIS', 'UTF-8'));
239+
$crawler->addContent(iconv('UTF-8', 'SJIS', '<html><head><meta charset="Shift_JIS"></head><body>日本語</body></html>'));
238240
$this->assertEquals('日本語', $crawler->filterXPath('//body')->text(), '->addContent() can recognize "Shift_JIS" in html5 meta charset tag');
239241
}
240242

src/Symfony/Component/Filesystem/Tests/FilesystemTest.php

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,13 @@ class FilesystemTest extends \PHPUnit_Framework_TestCase
3434

3535
public static function setUpBeforeClass()
3636
{
37-
if ('\\' === DIRECTORY_SEPARATOR) {
38-
self::$symlinkOnWindows = true;
39-
$originDir = tempnam(sys_get_temp_dir(), 'sl');
40-
$targetDir = tempnam(sys_get_temp_dir(), 'sl');
41-
if (true !== @symlink($originDir, $targetDir)) {
42-
$report = error_get_last();
43-
if (is_array($report) && false !== strpos($report['message'], 'error code(1314)')) {
44-
self::$symlinkOnWindows = false;
45-
}
37+
if ('\\' === DIRECTORY_SEPARATOR && null === self::$symlinkOnWindows) {
38+
$target = tempnam(sys_get_temp_dir(), 'sl');
39+
$link = sys_get_temp_dir().'/sl'.microtime(true).mt_rand();
40+
if (self::$symlinkOnWindows = @symlink($target, $link)) {
41+
unlink($link);
4642
}
43+
unlink($target);
4744
}
4845
}
4946

@@ -58,27 +55,10 @@ protected function setUp()
5855

5956
protected function tearDown()
6057
{
61-
$this->clean($this->workspace);
58+
$this->filesystem->remove($this->workspace);
6259
umask($this->umask);
6360
}
6461

65-
/**
66-
* @param string $file
67-
*/
68-
private function clean($file)
69-
{
70-
if (is_dir($file) && !is_link($file)) {
71-
$dir = new \FilesystemIterator($file);
72-
foreach ($dir as $childFile) {
73-
$this->clean($childFile);
74-
}
75-
76-
rmdir($file);
77-
} else {
78-
unlink($file);
79-
}
80-
}
81-
8262
public function testCopyCreatesNewFile()
8363
{
8464
$sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
@@ -1035,7 +1015,7 @@ private function markAsSkippedIfSymlinkIsMissing()
10351015
$this->markTestSkipped('symlink is not supported');
10361016
}
10371017

1038-
if ('\\' === DIRECTORY_SEPARATOR && false === self::$symlinkOnWindows) {
1018+
if (false === self::$symlinkOnWindows) {
10391019
$this->markTestSkipped('symlink requires "Create symbolic links" privilege on Windows');
10401020
}
10411021
}

src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@ public function testSeek($path, $seekable, $contains, $message = null)
6060
$i->seek(1);
6161
$actual[] = $i->getPathname();
6262

63-
$i->seek(2);
64-
$actual[] = $i->getPathname();
65-
6663
$this->assertEquals($contains, $actual);
6764
}
6865

@@ -73,7 +70,6 @@ public function getPaths()
7370
// ftp
7471
$contains = array(
7572
'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'README',
76-
'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'index.html',
7773
'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'pub',
7874
);
7975
$data[] = array('ftp://ftp.mozilla.org/', false, $contains);

src/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ public function testAccept($mode, $expected)
3333
if (!is_callable($mode)) {
3434
switch ($mode) {
3535
case SortableIterator::SORT_BY_ACCESSED_TIME :
36-
file_get_contents(self::toAbsolute('.git'));
36+
if ('\\' === DIRECTORY_SEPARATOR) {
37+
touch(self::toAbsolute('.git'));
38+
} else {
39+
file_get_contents(self::toAbsolute('.git'));
40+
}
3741
sleep(1);
3842
file_get_contents(self::toAbsolute('.bar'));
3943
break;
@@ -56,7 +60,11 @@ public function testAccept($mode, $expected)
5660

5761
if ($mode === SortableIterator::SORT_BY_ACCESSED_TIME
5862
|| $mode === SortableIterator::SORT_BY_CHANGED_TIME
59-
|| $mode === SortableIterator::SORT_BY_MODIFIED_TIME) {
63+
|| $mode === SortableIterator::SORT_BY_MODIFIED_TIME
64+
) {
65+
if ('\\' === DIRECTORY_SEPARATOR && SortableIterator::SORT_BY_MODIFIED_TIME !== $mode) {
66+
$this->markTestSkipped('Sorting by atime or ctime is not supported on Windows');
67+
}
6068
$this->assertOrderedIteratorForGroups($expected, $iterator);
6169
} else {
6270
$this->assertOrderedIterator($expected, $iterator);

src/Symfony/Component/Finder/Tests/Shell/CommandTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public function testArg()
8686
$cmd = Command::create()->add('--force');
8787

8888
$cmd->arg('--run');
89-
$this->assertSame('--force \'--run\'', $cmd->join());
89+
$this->assertSame('--force '.escapeshellarg('--run'), $cmd->join());
9090
}
9191

9292
public function testCmd()

src/Symfony/Component/Form/Extension/Core/Type/DateType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ private function formatTimestamps(\IntlDateFormatter $formatter, $regex, array $
260260
$pattern = $formatter->getPattern();
261261
$timezone = $formatter->getTimezoneId();
262262

263-
if ($setTimeZone = method_exists($formatter, 'setTimeZone')) {
263+
if ($setTimeZone = PHP_VERSION_ID >= 50500 || method_exists($formatter, 'setTimeZone')) {
264264
$formatter->setTimeZone('UTC');
265265
} else {
266266
$formatter->setTimeZoneId('UTC');

src/Symfony/Component/HttpFoundation/JsonResponse.php

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ class JsonResponse extends Response
2727
protected $data;
2828
protected $callback;
2929

30+
// Encode <, >, ', &, and " for RFC4627-compliant JSON, which may also be embedded into HTML.
31+
// 15 === JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT
32+
private $encodingOptions = 15;
33+
3034
/**
3135
* Constructor.
3236
*
@@ -41,6 +45,7 @@ public function __construct($data = null, $status = 200, $headers = array())
4145
if (null === $data) {
4246
$data = new \ArrayObject();
4347
}
48+
4449
$this->setData($data);
4550
}
4651

@@ -55,11 +60,11 @@ public static function create($data = null, $status = 200, $headers = array())
5560
/**
5661
* Sets the JSONP callback.
5762
*
58-
* @param string $callback
63+
* @param string|null $callback The JSONP callback or null to use none
5964
*
6065
* @return JsonResponse
6166
*
62-
* @throws \InvalidArgumentException
67+
* @throws \InvalidArgumentException When the callback name is not valid
6368
*/
6469
public function setCallback($callback = null)
6570
{
@@ -80,7 +85,7 @@ public function setCallback($callback = null)
8085
}
8186

8287
/**
83-
* Sets the data to be sent as json.
88+
* Sets the data to be sent as JSON.
8489
*
8590
* @param mixed $data
8691
*
@@ -90,18 +95,63 @@ public function setCallback($callback = null)
9095
*/
9196
public function setData($data = array())
9297
{
93-
// Encode <, >, ', &, and " for RFC4627-compliant JSON, which may also be embedded into HTML.
94-
$this->data = json_encode($data, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
98+
if (defined('HHVM_VERSION')) {
99+
// HHVM does not trigger any warnings and let exceptions
100+
// thrown from a JsonSerializable object pass through.
101+
// If only PHP did the same...
102+
$data = json_encode($data, $this->encodingOptions);
103+
} else {
104+
try {
105+
if (PHP_VERSION_ID < 50400) {
106+
// PHP 5.3 triggers annoying warnings for some
107+
// types that can't be serialized as JSON (INF, resources, etc.)
108+
// but doesn't provide the JsonSerializable interface.
109+
set_error_handler('var_dump', 0);
110+
$data = @json_encode($data, $this->encodingOptions);
111+
} else {
112+
// PHP 5.4 and up wrap exceptions thrown by JsonSerializable
113+
// objects in a new exception that needs to be removed.
114+
// Fortunately, PHP 5.5 and up do not trigger any warning anymore.
115+
if (PHP_VERSION_ID < 50500) {
116+
// Clear json_last_error()
117+
json_encode(null);
118+
$errorHandler = set_error_handler('var_dump');
119+
restore_error_handler();
120+
set_error_handler(function () use ($errorHandler) {
121+
if (JSON_ERROR_NONE === json_last_error()) {
122+
return $errorHandler && false !== call_user_func_array($errorHandler, func_get_args());
123+
}
124+
});
125+
}
126+
127+
$data = json_encode($data, $this->encodingOptions);
128+
}
129+
130+
if (PHP_VERSION_ID < 50500) {
131+
restore_error_handler();
132+
}
133+
} catch (\Exception $e) {
134+
if (PHP_VERSION_ID < 50500) {
135+
restore_error_handler();
136+
}
137+
if (PHP_VERSION_ID >= 50400 && 'Exception' === get_class($e) && 0 === strpos($e->getMessage(), 'Failed calling ')) {
138+
throw $e->getPrevious() ?: $e;
139+
}
140+
throw $e;
141+
}
142+
}
95143

96144
if (JSON_ERROR_NONE !== json_last_error()) {
97145
throw new \InvalidArgumentException($this->transformJsonError());
98146
}
99147

148+
$this->data = $data;
149+
100150
return $this->update();
101151
}
102152

103153
/**
104-
* Updates the content and headers according to the json data and callback.
154+
* Updates the content and headers according to the JSON data and callback.
105155
*
106156
* @return JsonResponse
107157
*/

src/Symfony/Component/HttpFoundation/Request.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,9 +1740,9 @@ protected function prepareBaseUrl()
17401740
return $prefix;
17411741
}
17421742

1743-
if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, rtrim(dirname($baseUrl), '/').'/')) {
1743+
if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, rtrim(dirname($baseUrl), '/'.DIRECTORY_SEPARATOR).'/')) {
17441744
// directory portion of $baseUrl matches
1745-
return rtrim($prefix, '/');
1745+
return rtrim($prefix, '/'.DIRECTORY_SEPARATOR);
17461746
}
17471747

17481748
$truncatedRequestUri = $requestUri;
@@ -1763,7 +1763,7 @@ protected function prepareBaseUrl()
17631763
$baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));
17641764
}
17651765

1766-
return rtrim($baseUrl, '/');
1766+
return rtrim($baseUrl, '/'.DIRECTORY_SEPARATOR);
17671767
}
17681768

17691769
/**

0 commit comments

Comments
 (0)
0