Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.5] Prevent Blade from parsing Blade code inside the @php and @endphp blocks #20065

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 33 additions & 14 deletions src/Illuminate/View/Compilers/BladeCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,18 +96,18 @@ class BladeCompiler extends Compiler implements CompilerInterface
protected $footer = [];

/**
* Placeholder to temporary mark the position of verbatim blocks.
* Placeholder to temporary mark the position of raw blocks.
*
* @var string
*/
protected $verbatimPlaceholder = '@__verbatim__@';
protected $rawPlaceholder = '@__raw-block__@';

/**
* Array to temporary store the verbatim blocks found in the template.
* Array to temporary store the raw blocks found in the template.
*
* @var array
*/
protected $verbatimBlocks = [];
protected $rawBlocks = [];

/**
* Compile the view at the given path.
Expand Down Expand Up @@ -157,23 +157,27 @@ public function setPath($path)
*/
public function compileString($value)
{
$result = '';

if (strpos($value, '@verbatim') !== false) {
$value = $this->storeVerbatimBlocks($value);
}

$this->footer = [];

if (strpos($value, '@php') !== false) {
$value = $this->storePhpBlocks($value);
}

$result = '';

// Here we will loop through all of the tokens returned by the Zend lexer and
// parse each one into the corresponding valid PHP. We will then have this
// template as the correctly rendered PHP that can be rendered natively.
foreach (token_get_all($value) as $token) {
$result .= is_array($token) ? $this->parseToken($token) : $token;
}

if (! empty($this->verbatimBlocks)) {
$result = $this->restoreVerbatimBlocks($result);
if (! empty($this->rawBlocks)) {
$result = $this->restoreRawContent($result);
}

// If there are any footer lines that need to get added to a template we will
Expand All @@ -195,9 +199,24 @@ public function compileString($value)
protected function storeVerbatimBlocks($value)
{
return preg_replace_callback('/(?<!@)@verbatim(.*?)@endverbatim/s', function ($matches) {
$this->verbatimBlocks[] = $matches[1];
$this->rawBlocks[] = $matches[1];

return $this->rawPlaceholder;
}, $value);
}

/**
* Store the PHP blocks and replace them with a temporary placeholder.
*
* @param string $value
* @return string
*/
protected function storePhpBlocks($value)
{
return preg_replace_callback('/(?<!@)@php(.*?)@endphp/s', function ($matches) {
$this->rawBlocks[] = "<?php{$matches[1]}?>";

return $this->verbatimPlaceholder;
return $this->rawPlaceholder;
}, $value);
}

Expand All @@ -207,13 +226,13 @@ protected function storeVerbatimBlocks($value)
* @param string $result
* @return string
*/
protected function restoreVerbatimBlocks($result)
protected function restoreRawContent($result)
{
$result = preg_replace_callback('/'.preg_quote($this->verbatimPlaceholder).'/', function () {
return array_shift($this->verbatimBlocks);
$result = preg_replace_callback('/'.preg_quote($this->rawPlaceholder).'/', function () {
return array_shift($this->rawBlocks);
}, $result);

$this->verbatimBlocks = [];
$this->rawBlocks = [];

return $result;
}
Expand Down
14 changes: 4 additions & 10 deletions src/Illuminate/View/Compilers/Concerns/CompilesRawPhp.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,11 @@ trait CompilesRawPhp
*/
protected function compilePhp($expression)
{
return $expression ? "<?php {$expression}; ?>" : '<?php ';
}
if ($expression) {
return "<?php {$expression}; ?>";
}

/**
* Compile end-php statements into valid PHP.
*
* @return string
*/
protected function compileEndphp()
{
return ' ?>';
return '@php';
}

/**
Expand Down
13 changes: 0 additions & 13 deletions tests/View/Blade/BladeEndphpStatementsTest.php

This file was deleted.

30 changes: 28 additions & 2 deletions tests/View/Blade/BladePhpStatementsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,36 @@ public function testPhpStatementsWithExpressionAreCompiled()
$this->assertEquals($expected, $this->compiler->compileString($string));
}

public function testPhpStatementsWithoutExpressionAreCompiled()
public function testPhpStatementsWithoutExpressionAreIgnored()
{
$string = '@php';
$expected = '<?php ';
$expected = '@php';
$this->assertEquals($expected, $this->compiler->compileString($string));

$string = '{{ "Ignore: @php" }}';
$expected = '<?php echo e("Ignore: @php"); ?>';
$this->assertEquals($expected, $this->compiler->compileString($string));
}

public function testPhpStatementsDontParseBladeCode()
{
$string = '@php echo "{{ This is a blade tag }}" @endphp';
$expected = '<?php echo "{{ This is a blade tag }}" ?>';
$this->assertEquals($expected, $this->compiler->compileString($string));
}

public function testVerbatimAndPhpStatementsDontGetMixedUp()
{
$string = "@verbatim {{ Hello, I'm not blade! }}"
."\n@php echo 'And I'm not PHP!' @endphp"
."\n@endverbatim {{ 'I am Blade' }}"
."\n@php echo 'I am PHP {{ not Blade }}' @endphp";

$expected = " {{ Hello, I'm not blade! }}"
."\n@php echo 'And I'm not PHP!' @endphp"
."\n <?php echo e('I am Blade'); ?>"
."\n\n<?php echo 'I am PHP {{ not Blade }}' ?>";

$this->assertEquals($expected, $this->compiler->compileString($string));
}
}