Skip to content

Commit 6550a9d

Browse files
Merge pull request #150 from lucasMesquitaBorges/fix-removing-trailing-slashes
Fix removing trailing slashes
2 parents 5c807f0 + 22118ff commit 6550a9d

File tree

5 files changed

+83
-19
lines changed

5 files changed

+83
-19
lines changed

src/Entities/HtmlSpecs.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace RenatoMarinho\LaravelPageSpeed\Entities;
4+
5+
class HtmlSpecs
6+
{
7+
public static function voidElements(): array
8+
{
9+
return [
10+
'area',
11+
'base',
12+
'br',
13+
'col',
14+
'embed',
15+
'hr',
16+
'img',
17+
'input',
18+
'link',
19+
'meta',
20+
'param',
21+
'source',
22+
'track',
23+
'wbr',
24+
];
25+
}
26+
}

src/Middleware/PageSpeed.php

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace RenatoMarinho\LaravelPageSpeed\Middleware;
44

55
use Closure;
6+
use RenatoMarinho\LaravelPageSpeed\Entities\HtmlSpecs;
67
use Symfony\Component\HttpFoundation\StreamedResponse;
78
use Symfony\Component\HttpFoundation\BinaryFileResponse;
89

@@ -109,10 +110,26 @@ protected function shouldProcessPageSpeed($request, $response)
109110
*/
110111
protected function matchAllHtmlTag(array $tags, string $buffer): array
111112
{
112-
$tags = '('.implode('|', $tags).')';
113+
$voidTags = array_intersect($tags, HtmlSpecs::voidElements());
114+
$normalTags = array_diff($tags, $voidTags);
113115

114-
preg_match_all("/\<\s*{$tags}[^>]*\>((.|\n)*?)\<\s*\/\s*{$tags}\>/", $buffer, $matches);
115-
return $matches;
116+
return array_merge(
117+
$this->matchTags($voidTags, '/\<\s*(%tags)[^>]*\>/', $buffer),
118+
$this->matchTags($normalTags, '/\<\s*(%tags)[^>]*\>((.|\n)*?)\<\s*\/\s*(%tags)\>/', $buffer)
119+
);
120+
}
121+
122+
protected function matchTags(array $tags, string $pattern, string $buffer): array
123+
{
124+
if (empty($tags)) {
125+
return [];
126+
}
127+
128+
$normalizedPattern = str_replace('%tags', implode('|', $tags), $pattern);
129+
130+
preg_match_all($normalizedPattern, $buffer, $matches);
131+
132+
return $matches[0];
116133
}
117134

118135
/**
@@ -127,12 +144,11 @@ protected function matchAllHtmlTag(array $tags, string $buffer): array
127144
*/
128145
protected function replaceInsideHtmlTags(array $tags, string $regex, string $replace, string $buffer): string
129146
{
130-
foreach ($this->matchAllHtmlTag($tags, $buffer)[0] as $tagMatched) {
131-
preg_match_all($regex, $tagMatched, $tagContentsMatchedToReplace);
147+
foreach ($this->matchAllHtmlTag($tags, $buffer) as $tagMatched) {
148+
preg_match_all($regex, $tagMatched, $contentsMatched);
132149

133-
foreach ($tagContentsMatchedToReplace[0] as $tagContentReplace) {
134-
$buffer = str_replace($tagContentReplace, $replace, $buffer);
135-
}
150+
$tagAfterReplace = str_replace($contentsMatched[0], $replace, $tagMatched);
151+
$buffer = str_replace($tagMatched, $tagAfterReplace, $buffer);
136152
}
137153

138154
return $buffer;

src/Middleware/RemoveQuotes.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22

33
namespace RenatoMarinho\LaravelPageSpeed\Middleware;
44

5+
use RenatoMarinho\LaravelPageSpeed\Entities\HtmlSpecs;
6+
57
class RemoveQuotes extends PageSpeed
68
{
79
public function apply($buffer)
810
{
11+
$buffer = $this->replaceInsideHtmlTags(HtmlSpecs::voidElements(), '/\/>/', '>', $buffer);
12+
913
$replace = [
1014
'/ src="(.\S*?)"/' => ' src=$1',
1115
'/ width="(.\S*?)"/' => ' width=$1',
@@ -16,7 +20,6 @@ public function apply($buffer)
1620
'/ border="(.\S*?)"/' => ' border=$1',
1721
'/ crossorigin="(.\S*?)"/' => ' crossorigin=$1',
1822
'/ type="(.\S*?)"/' => ' type=$1',
19-
'/\/>/' => '>',
2023
];
2124

2225
return $this->replace($replace, $buffer);

tests/Boilerplate/index.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@
4141
<div style="background-image: url('img/test-bg.jpg');">
4242
<h1>Test Background Image</h1>
4343
</div>
44+
45+
<svg width="325" height="200" xmlns="http://www.w3.org/2000/svg">
46+
<path d="M 80 80 A 45 45, 0, 0, 0, 125 125 L 125 80 Z" fill="green"/>
47+
<path d="M 230 80 A 45 45, 0, 1, 0, 275 125 L 275 80 Z" fill="red"/>
48+
</svg>
49+
4450
<img src="http://emblemsbf.com/img/18346.jpg" width="250" style="height:300px; padding:10px" />
4551

4652
<img src="tile whitespace.png" width="250" style="height:300px; padding:10px"/>

tests/Middleware/RemoveQuotesTest.php

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,35 @@
77

88
class RemoveQuotesTest extends TestCase
99
{
10+
protected $response;
11+
12+
public function setUp(): void
13+
{
14+
parent::setUp();
15+
16+
$this->response = $this->middleware->handle($this->request, $this->getNext());
17+
}
18+
1019
protected function getMiddleware()
1120
{
1221
$this->middleware = new RemoveQuotes();
1322
}
1423

1524
public function testRemoveQuotes()
1625
{
17-
$response = $this->middleware->handle($this->request, $this->getNext());
18-
19-
$this->assertStringContainsString('<link rel="apple-touch-icon" href="icon.png">', $response->getContent());
20-
$this->assertStringContainsString('<meta charset=utf-8>', $response->getContent());
21-
$this->assertStringContainsString('<meta name=viewport content="width=device-width, initial-scale=1">', $response->getContent());
22-
$this->assertStringContainsString('<img src=http://emblemsbf.com/img/18346.jpg width=250 style="height:300px; padding:10px" >', $response->getContent());
23-
$this->assertStringContainsString('<img src=/images/1000coin.png>', $response->getContent());
24-
$this->assertStringContainsString('<vue-component :src="\'src\'" :type="\'type\'" :width="200"></vue-component>', $response->getContent());
25-
$this->assertStringContainsString('<img src="tile whitespace.png" width=250 style="height:300px; padding:10px">', $response->getContent());
26-
$this->assertStringContainsString('<input type=text name="name with spaces" value="name with spaces" width=100%>', $response->getContent());
26+
$this->assertStringContainsString('<link rel="apple-touch-icon" href="icon.png">', $this->response->getContent());
27+
$this->assertStringContainsString('<meta charset=utf-8>', $this->response->getContent());
28+
$this->assertStringContainsString('<meta name=viewport content="width=device-width, initial-scale=1">', $this->response->getContent());
29+
$this->assertStringContainsString('<img src=http://emblemsbf.com/img/18346.jpg width=250 style="height:300px; padding:10px" >', $this->response->getContent());
30+
$this->assertStringContainsString('<img src=/images/1000coin.png>', $this->response->getContent());
31+
$this->assertStringContainsString('<vue-component :src="\'src\'" :type="\'type\'" :width="200"></vue-component>', $this->response->getContent());
32+
$this->assertStringContainsString('<img src="tile whitespace.png" width=250 style="height:300px; padding:10px">', $this->response->getContent());
33+
$this->assertStringContainsString('<input type=text name="name with spaces" value="name with spaces" width=100%>', $this->response->getContent());
34+
}
35+
36+
public function testWontRemoveTrailingSlashesOfNonVoidElements()
37+
{
38+
$this->assertStringContainsString('<path d="M 80 80 A 45 45, 0, 0, 0, 125 125 L 125 80 Z" fill="green"/>', $this->response->getContent());
39+
$this->assertStringContainsString('<path d="M 230 80 A 45 45, 0, 1, 0, 275 125 L 275 80 Z" fill="red"/>', $this->response->getContent());
2740
}
2841
}

0 commit comments

Comments
 (0)