Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
51.72% |
15 / 29 |
|
71.43% |
5 / 7 |
CRAP | |
0.00% |
0 / 1 |
loader | |
51.72% |
15 / 29 |
|
71.43% |
5 / 7 |
44.80 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setSafeDirectories | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
addSafeDirectory | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
getSafeDirectories | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
validateName | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
addPath | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
findTemplate | |
43.75% |
7 / 16 |
|
0.00% |
0 / 1 |
15.72 |
1 | <?php |
2 | /** |
3 | * |
4 | * This file is part of the phpBB Forum Software package. |
5 | * |
6 | * @copyright (c) phpBB Limited <https://www.phpbb.com> |
7 | * @license GNU General Public License, version 2 (GPL-2.0) |
8 | * |
9 | * For full copyright and license information, please see |
10 | * the docs/CREDITS.txt file. |
11 | * |
12 | */ |
13 | |
14 | namespace phpbb\template\twig; |
15 | |
16 | use phpbb\filesystem\helper as filesystem_helper; |
17 | |
18 | /** |
19 | * Twig Template loader |
20 | */ |
21 | class loader extends \Twig\Loader\FilesystemLoader |
22 | { |
23 | protected $safe_directories = array(); |
24 | |
25 | /** |
26 | * Constructor |
27 | * |
28 | * @param string|array $paths |
29 | */ |
30 | public function __construct($paths = array()) |
31 | { |
32 | parent::__construct($paths, __DIR__); |
33 | } |
34 | |
35 | /** |
36 | * Set safe directories |
37 | * |
38 | * @param array $directories Array of directories that are safe (empty to clear) |
39 | * @return \Twig\Loader\FilesystemLoader |
40 | */ |
41 | public function setSafeDirectories($directories = array()) |
42 | { |
43 | $this->safe_directories = array(); |
44 | |
45 | if (!empty($directories)) |
46 | { |
47 | foreach ($directories as $directory) |
48 | { |
49 | $this->addSafeDirectory($directory); |
50 | } |
51 | } |
52 | |
53 | return $this; |
54 | } |
55 | |
56 | /** |
57 | * Add safe directory |
58 | * |
59 | * @param string $directory Directory that should be added |
60 | * @return \Twig\Loader\FilesystemLoader |
61 | */ |
62 | public function addSafeDirectory($directory) |
63 | { |
64 | $directory = filesystem_helper::realpath($directory); |
65 | |
66 | if ($directory !== false) |
67 | { |
68 | $this->safe_directories[] = $directory; |
69 | } |
70 | |
71 | return $this; |
72 | } |
73 | |
74 | /** |
75 | * Get current safe directories |
76 | * |
77 | * @return array |
78 | */ |
79 | public function getSafeDirectories() |
80 | { |
81 | return $this->safe_directories; |
82 | } |
83 | |
84 | /** |
85 | * Override for parent::validateName() |
86 | * |
87 | * This is done because we added support for safe directories, and when Twig |
88 | * findTemplate() is called, validateName() is called first, which would |
89 | * always throw an exception if the file is outside of the configured |
90 | * template directories. |
91 | */ |
92 | protected function validateName($name) |
93 | { |
94 | return; |
95 | } |
96 | |
97 | /** |
98 | * Adds a realpath call to fix a BC break in Twig 1.26 (https://github.com/twigphp/Twig/issues/2145) |
99 | * |
100 | * {@inheritdoc} |
101 | */ |
102 | public function addPath($path, $namespace = self::MAIN_NAMESPACE) : void |
103 | { |
104 | parent::addPath(filesystem_helper::realpath($path), $namespace); |
105 | } |
106 | |
107 | /** |
108 | * Find the template |
109 | * |
110 | * Override for \Twig\Loader\FilesystemLoader::findTemplate |
111 | * to add support for loading from safe directories. |
112 | */ |
113 | protected function findTemplate($name, $throw = true) |
114 | { |
115 | $name = (string) $name; |
116 | |
117 | // normalize name |
118 | $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/')); |
119 | |
120 | // If this is in the cache we can skip the entire process below |
121 | // as it should have already been validated |
122 | if (isset($this->cache[$name])) |
123 | { |
124 | return $this->cache[$name]; |
125 | } |
126 | |
127 | // First, find the template name. The override above of validateName |
128 | // causes the validateName process to be skipped for this call |
129 | $file = parent::findTemplate($name, $throw); |
130 | |
131 | try |
132 | { |
133 | // Try validating the name (which may throw an exception) |
134 | $this->validateName($name); |
135 | } |
136 | catch (\Twig\Error\LoaderError $e) |
137 | { |
138 | if (strpos($e->getRawMessage(), 'Looks like you try to load a template outside configured directories') === 0) |
139 | { |
140 | // Ok, so outside of the configured template directories, we |
141 | // can now check if we're within a "safe" directory |
142 | |
143 | // Find the real path of the directory the file is in |
144 | $directory = filesystem_helper::realpath(dirname($file)); |
145 | |
146 | if ($directory === false) |
147 | { |
148 | // Some sort of error finding the actual path, must throw the exception |
149 | throw $e; |
150 | } |
151 | |
152 | foreach ($this->safe_directories as $safe_directory) |
153 | { |
154 | if (strpos($directory, $safe_directory) === 0) |
155 | { |
156 | // The directory being loaded is below a directory |
157 | // that is "safe". We're good to load it! |
158 | return $file; |
159 | } |
160 | } |
161 | } |
162 | |
163 | // Not within any safe directories |
164 | throw $e; |
165 | } |
166 | |
167 | // No exception from validateName, safe to load. |
168 | return $file; |
169 | } |
170 | } |