TYPO3 CMS  TYPO3_8-7
PharStreamWrapperInterceptorTest.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
20 
21 class PharStreamWrapperInterceptorTest extends FunctionalTestCase
22 {
29  'typo3/sysext/core/Tests/Functional/Fixtures/Extensions/test_resources' => 'typo3conf/ext/test_resources',
30  'typo3/sysext/core/Tests/Functional/Fixtures/Extensions/test_resources/bundle.phar' => 'fileadmin/bundle.phar',
31  ];
32 
33  protected function setUp()
34  {
35  parent::setUp();
36 
37  if (!in_array('phar', stream_get_wrappers())) {
38  $this->markTestSkipped('Phar stream wrapper is not registered');
39  }
40  // PharStreamWrapper is not initialized here since it relies on being
41  // properly defined in \TYPO3\CMS\Core\Core\Bootstrap - thus, it tests
42  // are expected to fail in case PharStreamWrapper is not initialized
43  }
44 
46  {
47  $allowedPath = 'typo3conf/ext/test_resources/bundle.phar';
48 
49  return [
50  'root directory' => [
51  $allowedPath,
52  ['Classes', 'Resources']
53  ],
54  'Classes/Domain/Model directory' => [
55  $allowedPath . '/Classes/Domain/Model',
56  ['DemoModel.php']
57  ],
58  'Resources directory' => [
59  $allowedPath . '/Resources',
60  ['content.txt']
61  ],
62  ];
63  }
64 
71  public function directoryOpenAllowsInvocation(string $path)
72  {
73  $path = $this->instancePath . '/' . $path;
74  $handle = opendir('phar://' . $path);
75  self::assertInternalType('resource', $handle);
76  }
77 
85  public function directoryReadAllowsInvocation(string $path, array $expectation)
86  {
87  $path = $this->instancePath . '/' . $path;
88 
89  $items = [];
90  $handle = opendir('phar://' . $path);
91  while (false !== $item = readdir($handle)) {
92  $items[] = $item;
93  }
94 
95  self::assertSame($expectation, $items);
96  }
97 
105  public function directoryCloseAllowsInvocation(string $path, array $expectation)
106  {
107  $path = $this->instancePath . '/' . $path;
108 
109  $handle = opendir('phar://' . $path);
110  closedir($handle);
111 
112  self::assertFalse(is_resource($handle));
113  }
114 
116  {
117  $deniedPath = 'fileadmin/bundle.phar';
118 
119  return [
120  'root directory' => [
121  $deniedPath,
122  ['Classes', 'Resources']
123  ],
124  'Classes/Domain/Model directory' => [
125  $deniedPath . '/Classes/Domain/Model',
126  ['DemoModel.php']
127  ],
128  'Resources directory' => [
129  $deniedPath . '/Resources',
130  ['content.txt']
131  ],
132  ];
133  }
134 
141  public function directoryActionDeniesInvocation(string $path)
142  {
143  self::expectException(Exception::class);
144  self::expectExceptionCode(1530103998);
145 
146  $path = $this->instancePath . '/' . $path;
147  opendir('phar://' . $path);
148  }
149 
153  public function urlStatAllowsInvocationDataProvider(): array
154  {
155  $allowedPath = 'typo3conf/ext/test_resources/bundle.phar';
156 
157  return [
158  'filesize base file' => [
159  'filesize',
160  $allowedPath,
161  0, // Phar base file always has zero size when accessed through phar://
162  ],
163  'filesize Resources/content.txt' => [
164  'filesize',
165  $allowedPath . '/Resources/content.txt',
166  21,
167  ],
168  'is_file base file' => [
169  'is_file',
170  $allowedPath,
171  false, // Phar base file is not a file when accessed through phar://
172  ],
173  'is_file Resources/content.txt' => [
174  'is_file',
175  $allowedPath . '/Resources/content.txt',
176  true,
177  ],
178  'is_dir base file' => [
179  'is_dir',
180  $allowedPath,
181  true, // Phar base file is a directory when accessed through phar://
182  ],
183  'is_dir Resources/content.txt' => [
184  'is_dir',
185  $allowedPath . '/Resources/content.txt',
186  false,
187  ],
188  'file_exists base file' => [
189  'file_exists',
190  $allowedPath,
191  true
192  ],
193  'file_exists Resources/content.txt' => [
194  'file_exists',
195  $allowedPath . '/Resources/content.txt',
196  true
197  ],
198  ];
199  }
200 
209  public function urlStatAllowsInvocation(string $functionName, string $path, $expectation)
210  {
211  $path = $this->instancePath . '/' . $path;
212 
213  self::assertSame(
214  $expectation,
215  call_user_func($functionName, 'phar://' . $path)
216  );
217  }
218 
222  public function urlStatDeniesInvocationDataProvider(): array
223  {
224  $deniedPath = 'fileadmin/bundle.phar';
225 
226  return [
227  'filesize base file' => [
228  'filesize',
229  $deniedPath,
230  0, // Phar base file always has zero size when accessed through phar://
231  ],
232  'filesize Resources/content.txt' => [
233  'filesize',
234  $deniedPath . '/Resources/content.txt',
235  21,
236  ],
237  'is_file base file' => [
238  'is_file',
239  $deniedPath,
240  false, // Phar base file is not a file when accessed through phar://
241  ],
242  'is_file Resources/content.txt' => [
243  'is_file',
244  $deniedPath . '/Resources/content.txt',
245  true,
246  ],
247  'is_dir base file' => [
248  'is_dir',
249  $deniedPath,
250  true, // Phar base file is a directory when accessed through phar://
251  ],
252  'is_dir Resources/content.txt' => [
253  'is_dir',
254  $deniedPath . '/Resources/content.txt',
255  false,
256  ],
257  'file_exists base file' => [
258  'file_exists',
259  $deniedPath,
260  true
261  ],
262  'file_exists Resources/content.txt' => [
263  'file_exists',
264  $deniedPath . '/Resources/content.txt',
265  true
266  ],
267  ];
268  }
269 
278  public function urlStatDeniesInvocation(string $functionName, string $path)
279  {
280  self::expectException(Exception::class);
281  self::expectExceptionCode(1530103998);
282 
283  $path = $this->instancePath . '/' . $path;
284  call_user_func($functionName, 'phar://' . $path);
285  }
286 
291  {
292  $allowedPath = $this->instancePath . '/typo3conf/ext/test_resources/bundle.phar';
293  $handle = fopen('phar://' . $allowedPath . '/Resources/content.txt', 'r');
294  self::assertInternalType('resource', $handle);
295  }
296 
301  {
302  $allowedPath = $this->instancePath . '/typo3conf/ext/test_resources/bundle.phar';
303  $handle = fopen('phar://' . $allowedPath . '/Resources/content.txt', 'r');
304  $content = fread($handle, 1024);
305  self::assertSame('TYPO3 demo text file.', $content);
306  }
307 
312  {
313  $allowedPath = $this->instancePath . '/typo3conf/ext/test_resources/bundle.phar';
314  $handle = fopen('phar://' . $allowedPath . '/Resources/content.txt', 'r');
315  fread($handle, 1024);
316  self::assertTrue(feof($handle));
317  }
318 
323  {
324  $allowedPath = $this->instancePath . '/typo3conf/ext/test_resources/bundle.phar';
325  $handle = fopen('phar://' . $allowedPath . '/Resources/content.txt', 'r');
326  fclose($handle);
327  self::assertFalse(is_resource($handle));
328  }
329 
334  {
335  $allowedPath = $this->instancePath . '/typo3conf/ext/test_resources/bundle.phar';
336  $content = file_get_contents('phar://' . $allowedPath . '/Resources/content.txt');
337  self::assertSame('TYPO3 demo text file.', $content);
338  }
339 
344  {
345  $allowedPath = $this->instancePath . '/typo3conf/ext/test_resources/bundle.phar';
346  include('phar://' . $allowedPath . '/Classes/Domain/Model/DemoModel.php');
347 
348  self::assertTrue(
349  class_exists(
350  \TYPO3Demo\Demo\Domain\Model\DemoModel::class,
351  false
352  )
353  );
354  }
355 
360  {
361  self::expectException(Exception::class);
362  self::expectExceptionCode(1530103998);
363 
364  $allowedPath = $this->instancePath . '/fileadmin/bundle.phar';
365  fopen('phar://' . $allowedPath . '/Resources/content.txt', 'r');
366  }
367 
372  {
373  self::expectException(Exception::class);
374  self::expectExceptionCode(1530103998);
375 
376  $allowedPath = $this->instancePath . '/fileadmin/bundle.phar';
377  file_get_contents('phar://' . $allowedPath . '/Resources/content.txt');
378  }
379 
384  {
385  self::expectException(Exception::class);
386  self::expectExceptionCode(1530103998);
387 
388  $allowedPath = $this->instancePath . '/fileadmin/bundle.phar';
389  include('phar://' . $allowedPath . '/Classes/Domain/Model/DemoModel.php');
390  }
391 }