]> git.immae.eu Git - github/wallabag/wallabag.git/blob - vendor/twig/twig/test/Twig/Tests/escapingTest.php
twig implementation
[github/wallabag/wallabag.git] / vendor / twig / twig / test / Twig / Tests / escapingTest.php
1 <?php
2
3 /**
4 * This class is adapted from code coming from Zend Framework.
5 *
6 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
8 */
9
10 class Twig_Test_EscapingTest extends PHPUnit_Framework_TestCase
11 {
12 /**
13 * All character encodings supported by htmlspecialchars()
14 */
15 protected $htmlSpecialChars = array(
16 '\'' => '&#039;',
17 '"' => '&quot;',
18 '<' => '&lt;',
19 '>' => '&gt;',
20 '&' => '&amp;'
21 );
22
23 protected $htmlAttrSpecialChars = array(
24 '\'' => '&#x27;',
25 /* Characters beyond ASCII value 255 to unicode escape */
26 'Ā' => '&#x0100;',
27 /* Immune chars excluded */
28 ',' => ',',
29 '.' => '.',
30 '-' => '-',
31 '_' => '_',
32 /* Basic alnums excluded */
33 'a' => 'a',
34 'A' => 'A',
35 'z' => 'z',
36 'Z' => 'Z',
37 '0' => '0',
38 '9' => '9',
39 /* Basic control characters and null */
40 "\r" => '&#x0D;',
41 "\n" => '&#x0A;',
42 "\t" => '&#x09;',
43 "\0" => '&#xFFFD;', // should use Unicode replacement char
44 /* Encode chars as named entities where possible */
45 '<' => '&lt;',
46 '>' => '&gt;',
47 '&' => '&amp;',
48 '"' => '&quot;',
49 /* Encode spaces for quoteless attribute protection */
50 ' ' => '&#x20;',
51 );
52
53 protected $jsSpecialChars = array(
54 /* HTML special chars - escape without exception to hex */
55 '<' => '\\x3C',
56 '>' => '\\x3E',
57 '\'' => '\\x27',
58 '"' => '\\x22',
59 '&' => '\\x26',
60 /* Characters beyond ASCII value 255 to unicode escape */
61 'Ā' => '\\u0100',
62 /* Immune chars excluded */
63 ',' => ',',
64 '.' => '.',
65 '_' => '_',
66 /* Basic alnums excluded */
67 'a' => 'a',
68 'A' => 'A',
69 'z' => 'z',
70 'Z' => 'Z',
71 '0' => '0',
72 '9' => '9',
73 /* Basic control characters and null */
74 "\r" => '\\x0D',
75 "\n" => '\\x0A',
76 "\t" => '\\x09',
77 "\0" => '\\x00',
78 /* Encode spaces for quoteless attribute protection */
79 ' ' => '\\x20',
80 );
81
82 protected $urlSpecialChars = array(
83 /* HTML special chars - escape without exception to percent encoding */
84 '<' => '%3C',
85 '>' => '%3E',
86 '\'' => '%27',
87 '"' => '%22',
88 '&' => '%26',
89 /* Characters beyond ASCII value 255 to hex sequence */
90 'Ā' => '%C4%80',
91 /* Punctuation and unreserved check */
92 ',' => '%2C',
93 '.' => '.',
94 '_' => '_',
95 '-' => '-',
96 ':' => '%3A',
97 ';' => '%3B',
98 '!' => '%21',
99 /* Basic alnums excluded */
100 'a' => 'a',
101 'A' => 'A',
102 'z' => 'z',
103 'Z' => 'Z',
104 '0' => '0',
105 '9' => '9',
106 /* Basic control characters and null */
107 "\r" => '%0D',
108 "\n" => '%0A',
109 "\t" => '%09',
110 "\0" => '%00',
111 /* PHP quirks from the past */
112 ' ' => '%20',
113 '~' => '~',
114 '+' => '%2B',
115 );
116
117 protected $cssSpecialChars = array(
118 /* HTML special chars - escape without exception to hex */
119 '<' => '\\3C ',
120 '>' => '\\3E ',
121 '\'' => '\\27 ',
122 '"' => '\\22 ',
123 '&' => '\\26 ',
124 /* Characters beyond ASCII value 255 to unicode escape */
125 'Ā' => '\\100 ',
126 /* Immune chars excluded */
127 ',' => '\\2C ',
128 '.' => '\\2E ',
129 '_' => '\\5F ',
130 /* Basic alnums excluded */
131 'a' => 'a',
132 'A' => 'A',
133 'z' => 'z',
134 'Z' => 'Z',
135 '0' => '0',
136 '9' => '9',
137 /* Basic control characters and null */
138 "\r" => '\\D ',
139 "\n" => '\\A ',
140 "\t" => '\\9 ',
141 "\0" => '\\0 ',
142 /* Encode spaces for quoteless attribute protection */
143 ' ' => '\\20 ',
144 );
145
146 protected $env;
147
148 public function setUp()
149 {
150 $this->env = new Twig_Environment();
151 }
152
153 public function testHtmlEscapingConvertsSpecialChars()
154 {
155 foreach ($this->htmlSpecialChars as $key => $value) {
156 $this->assertEquals($value, twig_escape_filter($this->env, $key, 'html'), 'Failed to escape: '.$key);
157 }
158 }
159
160 public function testHtmlAttributeEscapingConvertsSpecialChars()
161 {
162 foreach ($this->htmlAttrSpecialChars as $key => $value) {
163 $this->assertEquals($value, twig_escape_filter($this->env, $key, 'html_attr'), 'Failed to escape: '.$key);
164 }
165 }
166
167 public function testJavascriptEscapingConvertsSpecialChars()
168 {
169 foreach ($this->jsSpecialChars as $key => $value) {
170 $this->assertEquals($value, twig_escape_filter($this->env, $key, 'js'), 'Failed to escape: '.$key);
171 }
172 }
173
174 public function testJavascriptEscapingReturnsStringIfZeroLength()
175 {
176 $this->assertEquals('', twig_escape_filter($this->env, '', 'js'));
177 }
178
179 public function testJavascriptEscapingReturnsStringIfContainsOnlyDigits()
180 {
181 $this->assertEquals('123', twig_escape_filter($this->env, '123', 'js'));
182 }
183
184 public function testCssEscapingConvertsSpecialChars()
185 {
186 foreach ($this->cssSpecialChars as $key => $value) {
187 $this->assertEquals($value, twig_escape_filter($this->env, $key, 'css'), 'Failed to escape: '.$key);
188 }
189 }
190
191 public function testCssEscapingReturnsStringIfZeroLength()
192 {
193 $this->assertEquals('', twig_escape_filter($this->env, '', 'css'));
194 }
195
196 public function testCssEscapingReturnsStringIfContainsOnlyDigits()
197 {
198 $this->assertEquals('123', twig_escape_filter($this->env, '123', 'css'));
199 }
200
201 public function testUrlEscapingConvertsSpecialChars()
202 {
203 foreach ($this->urlSpecialChars as $key => $value) {
204 $this->assertEquals($value, twig_escape_filter($this->env, $key, 'url'), 'Failed to escape: '.$key);
205 }
206 }
207
208 /**
209 * Range tests to confirm escaped range of characters is within OWASP recommendation
210 */
211
212 /**
213 * Only testing the first few 2 ranges on this prot. function as that's all these
214 * other range tests require
215 */
216 public function testUnicodeCodepointConversionToUtf8()
217 {
218 $expected = " ~ޙ";
219 $codepoints = array(0x20, 0x7e, 0x799);
220 $result = '';
221 foreach ($codepoints as $value) {
222 $result .= $this->codepointToUtf8($value);
223 }
224 $this->assertEquals($expected, $result);
225 }
226
227 /**
228 * Convert a Unicode Codepoint to a literal UTF-8 character.
229 *
230 * @param int Unicode codepoint in hex notation
231 * @return string UTF-8 literal string
232 */
233 protected function codepointToUtf8($codepoint)
234 {
235 if ($codepoint < 0x80) {
236 return chr($codepoint);
237 }
238 if ($codepoint < 0x800) {
239 return chr($codepoint >> 6 & 0x3f | 0xc0)
240 . chr($codepoint & 0x3f | 0x80);
241 }
242 if ($codepoint < 0x10000) {
243 return chr($codepoint >> 12 & 0x0f | 0xe0)
244 . chr($codepoint >> 6 & 0x3f | 0x80)
245 . chr($codepoint & 0x3f | 0x80);
246 }
247 if ($codepoint < 0x110000) {
248 return chr($codepoint >> 18 & 0x07 | 0xf0)
249 . chr($codepoint >> 12 & 0x3f | 0x80)
250 . chr($codepoint >> 6 & 0x3f | 0x80)
251 . chr($codepoint & 0x3f | 0x80);
252 }
253 throw new Exception('Codepoint requested outside of Unicode range');
254 }
255
256 public function testJavascriptEscapingEscapesOwaspRecommendedRanges()
257 {
258 $immune = array(',', '.', '_'); // Exceptions to escaping ranges
259 for ($chr=0; $chr < 0xFF; $chr++) {
260 if ($chr >= 0x30 && $chr <= 0x39
261 || $chr >= 0x41 && $chr <= 0x5A
262 || $chr >= 0x61 && $chr <= 0x7A) {
263 $literal = $this->codepointToUtf8($chr);
264 $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'js'));
265 } else {
266 $literal = $this->codepointToUtf8($chr);
267 if (in_array($literal, $immune)) {
268 $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'js'));
269 } else {
270 $this->assertNotEquals(
271 $literal,
272 twig_escape_filter($this->env, $literal, 'js'),
273 "$literal should be escaped!");
274 }
275 }
276 }
277 }
278
279 public function testHtmlAttributeEscapingEscapesOwaspRecommendedRanges()
280 {
281 $immune = array(',', '.', '-', '_'); // Exceptions to escaping ranges
282 for ($chr=0; $chr < 0xFF; $chr++) {
283 if ($chr >= 0x30 && $chr <= 0x39
284 || $chr >= 0x41 && $chr <= 0x5A
285 || $chr >= 0x61 && $chr <= 0x7A) {
286 $literal = $this->codepointToUtf8($chr);
287 $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'html_attr'));
288 } else {
289 $literal = $this->codepointToUtf8($chr);
290 if (in_array($literal, $immune)) {
291 $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'html_attr'));
292 } else {
293 $this->assertNotEquals(
294 $literal,
295 twig_escape_filter($this->env, $literal, 'html_attr'),
296 "$literal should be escaped!");
297 }
298 }
299 }
300 }
301
302 public function testCssEscapingEscapesOwaspRecommendedRanges()
303 {
304 $immune = array(); // CSS has no exceptions to escaping ranges
305 for ($chr=0; $chr < 0xFF; $chr++) {
306 if ($chr >= 0x30 && $chr <= 0x39
307 || $chr >= 0x41 && $chr <= 0x5A
308 || $chr >= 0x61 && $chr <= 0x7A) {
309 $literal = $this->codepointToUtf8($chr);
310 $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'css'));
311 } else {
312 $literal = $this->codepointToUtf8($chr);
313 $this->assertNotEquals(
314 $literal,
315 twig_escape_filter($this->env, $literal, 'css'),
316 "$literal should be escaped!");
317 }
318 }
319 }
320 }