Skip to content

Commit

Permalink
feature #19079 [Debug] Do not quote numbers in stack trace (c960657)
Browse files Browse the repository at this point in the history
This PR was merged into the 3.2-dev branch.

Discussion
----------

[Debug] Do not quote numbers in stack trace

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | yes
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets |
| License       | MIT
| Doc PR        |

In the debug output from the exception handler, integers and floats are quoted. This adds unnecessary noise to the error page and is just wrong.

Fixing this requires introduces two new type descriptions in the output from getTrace(), so the change is not fully backwards compatible.

Commits
-------

fb10b33 [Debug] Do not quote numbers in stack trace
  • Loading branch information
fabpot committed Jun 19, 2016
2 parents afed2f8 + fb10b33 commit 414a4b4
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 48 deletions.
6 changes: 6 additions & 0 deletions UPGRADE-4.0.md
@@ -1,6 +1,12 @@
UPGRADE FROM 3.x to 4.0
=======================

Debug
-----

* `FlattenException::getTrace()` now returns additional type descriptions
`integer` and `float`.

DependencyInjection
-------------------

Expand Down
6 changes: 2 additions & 4 deletions src/Symfony/Bridge/Twig/Extension/CodeExtension.php
Expand Up @@ -92,16 +92,14 @@ public function formatArgs($args)
$formattedValue = sprintf('<em>object</em>(<abbr title="%s">%s</abbr>)', $item[1], $short);
} elseif ('array' === $item[0]) {
$formattedValue = sprintf('<em>array</em>(%s)', is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
} elseif ('string' === $item[0]) {
$formattedValue = sprintf("'%s'", htmlspecialchars($item[1], ENT_QUOTES, $this->charset));
} elseif ('null' === $item[0]) {
$formattedValue = '<em>null</em>';
} elseif ('boolean' === $item[0]) {
$formattedValue = '<em>'.strtolower(var_export($item[1], true)).'</em>';
} elseif ('resource' === $item[0]) {
$formattedValue = '<em>resource</em>';
} else {
$formattedValue = str_replace("\n", '', var_export(htmlspecialchars((string) $item[1], ENT_QUOTES, $this->charset), true));
$formattedValue = str_replace("\n", '', htmlspecialchars(var_export($item[1], true), ENT_COMPAT | ENT_SUBSTITUTE, $this->charset));
}

$result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", $key, $formattedValue);
Expand Down Expand Up @@ -174,7 +172,7 @@ public function formatFile($file, $line, $text = null)
$text = "$text at line $line";

if (false !== $link = $this->getFileLink($file, $line)) {
$flags = ENT_QUOTES | ENT_SUBSTITUTE;
$flags = ENT_COMPAT | ENT_SUBSTITUTE;

return sprintf('<a href="%s" title="Click to open this file" class="file_link">%s</a>', htmlspecialchars($link, $flags, $this->charset), $text);
}
Expand Down
7 changes: 7 additions & 0 deletions src/Symfony/Component/Debug/CHANGELOG.md
@@ -1,6 +1,13 @@
CHANGELOG
=========

3.2.0
-----

* `FlattenException::getTrace()` now returns additional type descriptions
`integer` and `float`.


3.0.0
-----

Expand Down
4 changes: 4 additions & 0 deletions src/Symfony/Component/Debug/Exception/FlattenException.php
Expand Up @@ -234,6 +234,10 @@ private function flattenArgs($args, $level = 0, &$count = 0)
$result[$key] = array('null', null);
} elseif (is_bool($value)) {
$result[$key] = array('boolean', $value);
} elseif (is_integer($value)) {
$result[$key] = array('integer', $value);
} elseif (is_float($value)) {
$result[$key] = array('float', $value);
} elseif (is_resource($value)) {
$result[$key] = array('resource', get_resource_type($value));
} elseif ($value instanceof \__PHP_Incomplete_Class) {
Expand Down
4 changes: 1 addition & 3 deletions src/Symfony/Component/Debug/ExceptionHandler.php
Expand Up @@ -376,16 +376,14 @@ private function formatArgs(array $args)
$formattedValue = sprintf('<em>object</em>(%s)', $this->formatClass($item[1]));
} elseif ('array' === $item[0]) {
$formattedValue = sprintf('<em>array</em>(%s)', is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
} elseif ('string' === $item[0]) {
$formattedValue = sprintf("'%s'", $this->escapeHtml($item[1]));
} elseif ('null' === $item[0]) {
$formattedValue = '<em>null</em>';
} elseif ('boolean' === $item[0]) {
$formattedValue = '<em>'.strtolower(var_export($item[1], true)).'</em>';
} elseif ('resource' === $item[0]) {
$formattedValue = '<em>resource</em>';
} else {
$formattedValue = str_replace("\n", '', var_export($this->escapeHtml((string) $item[1]), true));
$formattedValue = str_replace("\n", '', $this->escapeHtml(var_export($item[1], true)));
}

$result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", $key, $formattedValue);
Expand Down
Expand Up @@ -190,6 +190,60 @@ public function flattenDataProvider()
);
}

public function testArguments()
{
$dh = opendir(__DIR__);

$incomplete = unserialize('O:14:"BogusTestClass":0:{}');

$exception = $this->createException(array(
(object) array('foo' => 1),
new NotFoundHttpException(),
$incomplete,
$dh,
function() {},
array(1, 2),
array('foo' => 123),
null,
true,
false,
0,
0.0,
'0',
'',
INF,
NAN,
));

$flattened = FlattenException::create($exception);
$trace = $flattened->getTrace();
$args = $trace[1]['args'];
$array = $args[0][1];

closedir($dh);

$i = 0;
$this->assertSame($array[$i++], array('object', 'stdClass'));
$this->assertSame($array[$i++], array('object', 'Symfony\Component\HttpKernel\Exception\NotFoundHttpException'));
$this->assertSame($array[$i++], array('incomplete-object', 'BogusTestClass'));
$this->assertSame($array[$i++], array('resource', 'stream'));
$this->assertSame($array[$i++], array('object', 'Closure'));
$this->assertSame($array[$i++], array('array', array(array('integer', 1), array('integer', 2))));
$this->assertSame($array[$i++], array('array', array('foo' => array('integer', 123))));
$this->assertSame($array[$i++], array('null', null));
$this->assertSame($array[$i++], array('boolean', true));
$this->assertSame($array[$i++], array('boolean', false));
$this->assertSame($array[$i++], array('integer', 0));
$this->assertSame($array[$i++], array('float', 0.0));
$this->assertSame($array[$i++], array('string', '0'));
$this->assertSame($array[$i++], array('string', ''));
$this->assertSame($array[$i++], array('float', INF));

// assertEquals() does not like NAN values.
$this->assertEquals($array[$i][0], 'float');
$this->assertTrue(is_nan($array[$i++][1]));
}

public function testRecursionInArguments()
{
$a = array('foo', array(2, &$a));
Expand All @@ -216,6 +270,9 @@ public function testTooBigArray()

$flattened = FlattenException::create($exception);
$trace = $flattened->getTrace();

$this->assertSame($trace[1]['args'][0], array('array', array('array', '*SKIPPED over 10000 entries*')));

$serializeTrace = serialize($trace);

$this->assertContains('*SKIPPED over 10000 entries*', $serializeTrace);
Expand All @@ -226,45 +283,4 @@ private function createException($foo)
{
return new \Exception();
}

public function testSetTraceIncompleteClass()
{
$flattened = FlattenException::create(new \Exception('test', 123));
$flattened->setTrace(
array(
array(
'file' => __FILE__,
'line' => 123,
'function' => 'test',
'args' => array(
unserialize('O:14:"BogusTestClass":0:{}'),
),
),
),
'foo.php', 123
);

$this->assertEquals(array(
array(
'message' => 'test',
'class' => 'Exception',
'trace' => array(
array(
'namespace' => '', 'short_class' => '', 'class' => '', 'type' => '', 'function' => '',
'file' => 'foo.php', 'line' => 123,
'args' => array(),
),
array(
'namespace' => '', 'short_class' => '', 'class' => '', 'type' => '', 'function' => 'test',
'file' => __FILE__, 'line' => 123,
'args' => array(
array(
'incomplete-object', 'BogusTestClass',
),
),
),
),
),
), $flattened->toArray());
}
}

0 comments on commit 414a4b4

Please sign in to comment.