diff --git a/src/Symfony/Component/HttpKernel/HttpCache/Esi.php b/src/Symfony/Component/HttpKernel/HttpCache/Esi.php
index cd6a00a10d61f..4d86508a42092 100644
--- a/src/Symfony/Component/HttpKernel/HttpCache/Esi.php
+++ b/src/Symfony/Component/HttpKernel/HttpCache/Esi.php
@@ -80,8 +80,10 @@ public function process(Request $request, Response $response)
$content = preg_replace('#.*?#s', '', $content);
$content = preg_replace('#]+>#s', '', $content);
+ static $cookie;
+ $cookie = hash('md5', $cookie ?? $cookie = random_bytes(16), true);
+ $boundary = base64_encode($cookie);
$chunks = preg_split('##', $content, -1, \PREG_SPLIT_DELIM_CAPTURE);
- $chunks[0] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[0]);
$i = 1;
while (isset($chunks[$i])) {
@@ -95,16 +97,10 @@ public function process(Request $request, Response $response)
throw new \RuntimeException('Unable to process an ESI tag without a "src" attribute.');
}
- $chunks[$i] = sprintf('surrogate->handle($this, %s, %s, %s) ?>'."\n",
- var_export($options['src'], true),
- var_export($options['alt'] ?? '', true),
- isset($options['onerror']) && 'continue' === $options['onerror'] ? 'true' : 'false'
- );
- ++$i;
- $chunks[$i] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[$i]);
- ++$i;
+ $chunks[$i] = $boundary.$options['src']."\n".($options['alt'] ?? '')."\n".('continue' === ($options['onerror'] ?? ''))."\n";
+ $i += 2;
}
- $content = implode('', $chunks);
+ $content = $boundary.implode('', $chunks).$boundary;
$response->setContent($content);
$response->headers->set('X-Body-Eval', 'ESI');
diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
index 5688fc0c13ccd..063d4105b160b 100644
--- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
+++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php
@@ -636,7 +636,21 @@ private function restoreResponseBody(Request $request, Response $response)
if ($response->headers->has('X-Body-File')) {
include $response->headers->get('X-Body-File');
} else {
- eval('; ?>'.$response->getContent().'getContent();
+
+ if (substr($content, -24) === $boundary = substr($content, 0, 24)) {
+ $j = strpos($content, $boundary, 24);
+ echo substr($content, 24, $j - 24);
+ $i = $j + 24;
+
+ while (false !== $j = strpos($content, $boundary, $i)) {
+ [$uri, $alt, $ignoreErrors, $part] = explode("\n", substr($content, $i, $j - $i), 4);
+ $i = $j + 24;
+
+ echo $this->surrogate->handle($this, $uri, $alt, $ignoreErrors);
+ echo $part;
+ }
+ }
}
$response->setContent(ob_get_clean());
diff --git a/src/Symfony/Component/HttpKernel/HttpCache/Ssi.php b/src/Symfony/Component/HttpKernel/HttpCache/Ssi.php
index f114e05cfb2f6..bb48238ff1f4b 100644
--- a/src/Symfony/Component/HttpKernel/HttpCache/Ssi.php
+++ b/src/Symfony/Component/HttpKernel/HttpCache/Ssi.php
@@ -65,8 +65,10 @@ public function process(Request $request, Response $response)
// we don't use a proper XML parser here as we can have SSI tags in a plain text response
$content = $response->getContent();
+ static $cookie;
+ $cookie = hash('md5', $cookie ?? $cookie = random_bytes(16), true);
+ $boundary = base64_encode($cookie);
$chunks = preg_split('##', $content, -1, \PREG_SPLIT_DELIM_CAPTURE);
- $chunks[0] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[0]);
$i = 1;
while (isset($chunks[$i])) {
@@ -80,14 +82,10 @@ public function process(Request $request, Response $response)
throw new \RuntimeException('Unable to process an SSI tag without a "virtual" attribute.');
}
- $chunks[$i] = sprintf('surrogate->handle($this, %s, \'\', false) ?>'."\n",
- var_export($options['virtual'], true)
- );
- ++$i;
- $chunks[$i] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[$i]);
- ++$i;
+ $chunks[$i] = $boundary.$options['virtual']."\n\n\n";
+ $i += 2;
}
- $content = implode('', $chunks);
+ $content = $boundary.implode('', $chunks).$boundary;
$response->setContent($content);
$response->headers->set('X-Body-Eval', 'SSI');
diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/EsiTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/EsiTest.php
index 290bd94bdcb97..e876f28189087 100644
--- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/EsiTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/EsiTest.php
@@ -102,7 +102,7 @@ public function testMultilineEsiRemoveTagsAreRemoved()
$response = new Response(' www.example.com Keep this'."\n www.example.com And this");
$this->assertSame($response, $esi->process($request, $response));
- $this->assertEquals(' Keep this And this', $response->getContent());
+ $this->assertEquals(' Keep this And this', substr($response->getContent(), 24, -24));
}
public function testCommentTagsAreRemoved()
@@ -113,7 +113,7 @@ public function testCommentTagsAreRemoved()
$response = new Response(' Keep this');
$this->assertSame($response, $esi->process($request, $response));
- $this->assertEquals(' Keep this', $response->getContent());
+ $this->assertEquals(' Keep this', substr($response->getContent(), 24, -24));
}
public function testProcess()
@@ -124,23 +124,27 @@ public function testProcess()
$response = new Response('foo ');
$this->assertSame($response, $esi->process($request, $response));
- $this->assertEquals('foo surrogate->handle($this, \'...\', \'alt\', true) ?>'."\n", $response->getContent());
+ $content = explode(substr($response->getContent(), 0, 24), $response->getContent());
+ $this->assertSame(['', 'foo ', "...\nalt\n1\n", ''], $content);
$this->assertEquals('ESI', $response->headers->get('x-body-eval'));
$response = new Response('foo ');
$this->assertSame($response, $esi->process($request, $response));
- $this->assertEquals('foo surrogate->handle($this, \'foo\\\'\', \'bar\\\'\', true) ?>'."\n", $response->getContent());
+ $content = explode(substr($response->getContent(), 0, 24), $response->getContent());
+ $this->assertSame(['', 'foo ', "foo'\nbar'\n1\n", ''], $content);
$response = new Response('foo ');
$this->assertSame($response, $esi->process($request, $response));
- $this->assertEquals('foo surrogate->handle($this, \'...\', \'\', false) ?>'."\n", $response->getContent());
+ $content = explode(substr($response->getContent(), 0, 24), $response->getContent());
+ $this->assertSame(['', 'foo ', "...\n\n\n", ''], $content);
$response = new Response('foo ');
$this->assertSame($response, $esi->process($request, $response));
- $this->assertEquals('foo surrogate->handle($this, \'...\', \'\', false) ?>'."\n", $response->getContent());
+ $content = explode(substr($response->getContent(), 0, 24), $response->getContent());
+ $this->assertSame(['', 'foo ', "...\n\n\n", ''], $content);
}
public function testProcessEscapesPhpTags()
@@ -151,7 +155,8 @@ public function testProcessEscapesPhpTags()
$response = new Response('');
$this->assertSame($response, $esi->process($request, $response));
- $this->assertEquals('php cript language=php>', $response->getContent());
+ $content = explode(substr($response->getContent(), 0, 24), $response->getContent());
+ $this->assertSame(['', '', ''], $content);
}
public function testProcessWhenNoSrcInAnEsi()
diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/SsiTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/SsiTest.php
index a1f1f1593d3f3..97cc8fccd03d0 100644
--- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/SsiTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/SsiTest.php
@@ -101,13 +101,15 @@ public function testProcess()
$response = new Response('foo ');
$ssi->process($request, $response);
- $this->assertEquals('foo surrogate->handle($this, \'...\', \'\', false) ?>'."\n", $response->getContent());
+ $content = explode(substr($response->getContent(), 0, 24), $response->getContent());
+ $this->assertSame(['', 'foo ', "...\n\n\n", ''], $content);
$this->assertEquals('SSI', $response->headers->get('x-body-eval'));
$response = new Response('foo ');
$ssi->process($request, $response);
- $this->assertEquals("foo surrogate->handle(\$this, 'foo\\'', '', false) ?>\n", $response->getContent());
+ $content = explode(substr($response->getContent(), 0, 24), $response->getContent());
+ $this->assertSame(['', 'foo ', "foo'\n\n\n", ''], $content);
}
public function testProcessEscapesPhpTags()
@@ -118,7 +120,8 @@ public function testProcessEscapesPhpTags()
$response = new Response('');
$ssi->process($request, $response);
- $this->assertEquals('php cript language=php>', $response->getContent());
+ $content = explode(substr($response->getContent(), 0, 24), $response->getContent());
+ $this->assertSame(['', '', ''], $content);
}
public function testProcessWhenNoSrcInAnSsi()