Don't clear PHP buffer when an error occurs with debug=true

This commit is contained in:
Grégoire Pineau
2019-06-06 16:16:15 +02:00
committed by Fabien Potencier
parent 2a293b6827
commit c910e71f5a
9 changed files with 86 additions and 9 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
* 1.42.2 (2019-XX-XX) * 1.42.2 (2019-XX-XX)
* n/a * Display partial output (PHP buffer) when an error occurs in debug mode
* 1.42.1 (2019-06-04) * 1.42.1 (2019-06-04)
+1 -1
View File
@@ -54,7 +54,7 @@ function twig_var_dump(Environment $env, $context, array $vars = [])
return; return;
} }
ob_start(function () { return ''; }); ob_start();
if (!$vars) { if (!$vars) {
$vars = []; $vars = [];
+7 -1
View File
@@ -104,7 +104,13 @@ class MacroNode extends Node
->outdent() ->outdent()
->write("]);\n\n") ->write("]);\n\n")
->write("\$blocks = [];\n\n") ->write("\$blocks = [];\n\n")
->write("ob_start(function () { return ''; });\n") ;
if ($compiler->getEnvironment()->isDebug()) {
$compiler->write("ob_start();\n");
} else {
$compiler->write("ob_start(function () { return ''; });\n");
}
$compiler
->write("try {\n") ->write("try {\n")
->indent() ->indent()
->subcompile($this->getNode('body')) ->subcompile($this->getNode('body'))
+5 -1
View File
@@ -57,8 +57,12 @@ class SetNode extends Node implements NodeCaptureInterface
$compiler->raw(')'); $compiler->raw(')');
} else { } else {
if ($this->getAttribute('capture')) { if ($this->getAttribute('capture')) {
if ($compiler->getEnvironment()->isDebug()) {
$compiler->write("ob_start();\n");
} else {
$compiler->write("ob_start(function () { return ''; });\n");
}
$compiler $compiler
->write("ob_start(function () { return ''; });\n")
->subcompile($this->getNode('values')) ->subcompile($this->getNode('values'))
; ;
} }
+7 -1
View File
@@ -31,7 +31,13 @@ class SpacelessNode extends Node
{ {
$compiler $compiler
->addDebugInfo($this) ->addDebugInfo($this)
->write("ob_start(function () { return ''; });\n") ;
if ($compiler->getEnvironment()->isDebug()) {
$compiler->write("ob_start();\n");
} else {
$compiler->write("ob_start(function () { return ''; });\n");
}
$compiler
->subcompile($this->getNode('body')) ->subcompile($this->getNode('body'))
->write("echo trim(preg_replace('/>\s+</', '><', ob_get_clean()));\n") ->write("echo trim(preg_replace('/>\s+</', '><', ob_get_clean()));\n")
; ;
+15 -3
View File
@@ -253,7 +253,11 @@ abstract class Template implements \Twig_TemplateInterface
*/ */
public function renderParentBlock($name, array $context, array $blocks = []) public function renderParentBlock($name, array $context, array $blocks = [])
{ {
ob_start(function () { return ''; }); if ($this->env->isDebug()) {
ob_start();
} else {
ob_start(function () { return ''; });
}
$this->displayParentBlock($name, $context, $blocks); $this->displayParentBlock($name, $context, $blocks);
return ob_get_clean(); return ob_get_clean();
@@ -274,7 +278,11 @@ abstract class Template implements \Twig_TemplateInterface
*/ */
public function renderBlock($name, array $context, array $blocks = [], $useBlocks = true) public function renderBlock($name, array $context, array $blocks = [], $useBlocks = true)
{ {
ob_start(function () { return ''; }); if ($this->env->isDebug()) {
ob_start();
} else {
ob_start(function () { return ''; });
}
$this->displayBlock($name, $context, $blocks, $useBlocks); $this->displayBlock($name, $context, $blocks, $useBlocks);
return ob_get_clean(); return ob_get_clean();
@@ -417,7 +425,11 @@ abstract class Template implements \Twig_TemplateInterface
public function render(array $context) public function render(array $context)
{ {
$level = ob_get_level(); $level = ob_get_level();
ob_start(function () { return ''; }); if ($this->env->isDebug()) {
ob_start();
} else {
ob_start(function () { return ''; });
}
try { try {
$this->display($context); $this->display($context);
} catch (\Exception $e) { } catch (\Exception $e) {
+5 -1
View File
@@ -96,7 +96,11 @@ final class TemplateWrapper
{ {
$context = $this->env->mergeGlobals($context); $context = $this->env->mergeGlobals($context);
$level = ob_get_level(); $level = ob_get_level();
ob_start(function () { return ''; }); if ($this->env->isDebug()) {
ob_start();
} else {
ob_start(function () { return ''; });
}
try { try {
$this->template->displayBlock($name, $context); $this->template->displayBlock($name, $context);
} catch (\Exception $e) { } catch (\Exception $e) {
+14
View File
@@ -207,6 +207,20 @@ EOHTML
], ],
]; ];
} }
public function testTwigLeakOutputInDebugMode()
{
$output = exec(sprintf('%s %s debug', \PHP_BINARY, __DIR__.'/Fixtures/errors/leak-output.php'));
$this->assertSame('Hello OOPS', $output);
}
public function testDoesNotTwigLeakOutput()
{
$output = exec(sprintf('%s %s', \PHP_BINARY, __DIR__.'/Fixtures/errors/leak-output.php'));
$this->assertSame('', $output);
}
} }
class Twig_Tests_ErrorTest_Foo class Twig_Tests_ErrorTest_Foo
@@ -0,0 +1,31 @@
<?php
require __DIR__.'/../../../../../vendor/autoload.php';
use Twig\Environment;
use Twig\Extension\AbstractExtension;
use Twig\Loader\ArrayLoader;
use Twig\TwigFilter;
class BrokenExtension extends AbstractExtension
{
public function getFilters()
{
return [
new TwigFilter('broken', [$this, 'broken']),
];
}
public function broken()
{
die('OOPS');
}
}
$loader = new ArrayLoader([
'index.html.twig' => 'Hello {{ "world"|broken }}',
]);
$twig = new Environment($loader, ['debug' => isset($argv[1])]);
$twig->addExtension(new BrokenExtension());
echo $twig->render('index.html.twig');