9149bc3ea46ff2651527f890537e972b70444c18
[yaffs-website] / vendor / twig / twig / lib / Twig / Loader / Filesystem.php
1 <?php
2
3 /*
4  * This file is part of Twig.
5  *
6  * (c) Fabien Potencier
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 /**
13  * Loads template from the filesystem.
14  *
15  * @author Fabien Potencier <fabien@symfony.com>
16  */
17 class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
18 {
19     /** Identifier of the main namespace. */
20     const MAIN_NAMESPACE = '__main__';
21
22     protected $paths = array();
23     protected $cache = array();
24     protected $errorCache = array();
25
26     private $rootPath;
27
28     /**
29      * @param string|array $paths    A path or an array of paths where to look for templates
30      * @param string|null  $rootPath The root path common to all relative paths (null for getcwd())
31      */
32     public function __construct($paths = array(), $rootPath = null)
33     {
34         $this->rootPath = (null === $rootPath ? getcwd() : $rootPath).DIRECTORY_SEPARATOR;
35         if (false !== $realPath = realpath($rootPath)) {
36             $this->rootPath = $realPath.DIRECTORY_SEPARATOR;
37         }
38
39         if ($paths) {
40             $this->setPaths($paths);
41         }
42     }
43
44     /**
45      * Returns the paths to the templates.
46      *
47      * @param string $namespace A path namespace
48      *
49      * @return array The array of paths where to look for templates
50      */
51     public function getPaths($namespace = self::MAIN_NAMESPACE)
52     {
53         return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array();
54     }
55
56     /**
57      * Returns the path namespaces.
58      *
59      * The main namespace is always defined.
60      *
61      * @return array The array of defined namespaces
62      */
63     public function getNamespaces()
64     {
65         return array_keys($this->paths);
66     }
67
68     /**
69      * Sets the paths where templates are stored.
70      *
71      * @param string|array $paths     A path or an array of paths where to look for templates
72      * @param string       $namespace A path namespace
73      */
74     public function setPaths($paths, $namespace = self::MAIN_NAMESPACE)
75     {
76         if (!is_array($paths)) {
77             $paths = array($paths);
78         }
79
80         $this->paths[$namespace] = array();
81         foreach ($paths as $path) {
82             $this->addPath($path, $namespace);
83         }
84     }
85
86     /**
87      * Adds a path where templates are stored.
88      *
89      * @param string $path      A path where to look for templates
90      * @param string $namespace A path namespace
91      *
92      * @throws Twig_Error_Loader
93      */
94     public function addPath($path, $namespace = self::MAIN_NAMESPACE)
95     {
96         // invalidate the cache
97         $this->cache = $this->errorCache = array();
98
99         $checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
100         if (!is_dir($checkPath)) {
101             throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
102         }
103
104         $this->paths[$namespace][] = rtrim($path, '/\\');
105     }
106
107     /**
108      * Prepends a path where templates are stored.
109      *
110      * @param string $path      A path where to look for templates
111      * @param string $namespace A path namespace
112      *
113      * @throws Twig_Error_Loader
114      */
115     public function prependPath($path, $namespace = self::MAIN_NAMESPACE)
116     {
117         // invalidate the cache
118         $this->cache = $this->errorCache = array();
119
120         $checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
121         if (!is_dir($checkPath)) {
122             throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
123         }
124
125         $path = rtrim($path, '/\\');
126
127         if (!isset($this->paths[$namespace])) {
128             $this->paths[$namespace][] = $path;
129         } else {
130             array_unshift($this->paths[$namespace], $path);
131         }
132     }
133
134     public function getSource($name)
135     {
136         @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
137
138         return file_get_contents($this->findTemplate($name));
139     }
140
141     public function getSourceContext($name)
142     {
143         $path = $this->findTemplate($name);
144
145         return new Twig_Source(file_get_contents($path), $name, $path);
146     }
147
148     public function getCacheKey($name)
149     {
150         $path = $this->findTemplate($name);
151         $len = strlen($this->rootPath);
152         if (0 === strncmp($this->rootPath, $path, $len)) {
153             return substr($path, $len);
154         }
155
156         return $path;
157     }
158
159     public function exists($name)
160     {
161         $name = $this->normalizeName($name);
162
163         if (isset($this->cache[$name])) {
164             return true;
165         }
166
167         try {
168             return false !== $this->findTemplate($name, false);
169         } catch (Twig_Error_Loader $exception) {
170             @trigger_error(sprintf('In %s::findTemplate(), you must accept a second argument that when set to "false" returns "false" instead of throwing an exception. Not supporting this argument is deprecated since version 1.27.', get_class($this)), E_USER_DEPRECATED);
171
172             return false;
173         }
174     }
175
176     public function isFresh($name, $time)
177     {
178         return filemtime($this->findTemplate($name)) <= $time;
179     }
180
181     protected function findTemplate($name)
182     {
183         $throw = func_num_args() > 1 ? func_get_arg(1) : true;
184         $name = $this->normalizeName($name);
185
186         if (isset($this->cache[$name])) {
187             return $this->cache[$name];
188         }
189
190         if (isset($this->errorCache[$name])) {
191             if (!$throw) {
192                 return false;
193             }
194
195             throw new Twig_Error_Loader($this->errorCache[$name]);
196         }
197
198         $this->validateName($name);
199
200         list($namespace, $shortname) = $this->parseName($name);
201
202         if (!isset($this->paths[$namespace])) {
203             $this->errorCache[$name] = sprintf('There are no registered paths for namespace "%s".', $namespace);
204
205             if (!$throw) {
206                 return false;
207             }
208
209             throw new Twig_Error_Loader($this->errorCache[$name]);
210         }
211
212         foreach ($this->paths[$namespace] as $path) {
213             if (!$this->isAbsolutePath($path)) {
214                 $path = $this->rootPath.'/'.$path;
215             }
216
217             if (is_file($path.'/'.$shortname)) {
218                 if (false !== $realpath = realpath($path.'/'.$shortname)) {
219                     return $this->cache[$name] = $realpath;
220                 }
221
222                 return $this->cache[$name] = $path.'/'.$shortname;
223             }
224         }
225
226         $this->errorCache[$name] = sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace]));
227
228         if (!$throw) {
229             return false;
230         }
231
232         throw new Twig_Error_Loader($this->errorCache[$name]);
233     }
234
235     protected function parseName($name, $default = self::MAIN_NAMESPACE)
236     {
237         if (isset($name[0]) && '@' == $name[0]) {
238             if (false === $pos = strpos($name, '/')) {
239                 throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
240             }
241
242             $namespace = substr($name, 1, $pos - 1);
243             $shortname = substr($name, $pos + 1);
244
245             return array($namespace, $shortname);
246         }
247
248         return array($default, $name);
249     }
250
251     protected function normalizeName($name)
252     {
253         return preg_replace('#/{2,}#', '/', str_replace('\\', '/', (string) $name));
254     }
255
256     protected function validateName($name)
257     {
258         if (false !== strpos($name, "\0")) {
259             throw new Twig_Error_Loader('A template name cannot contain NUL bytes.');
260         }
261
262         $name = ltrim($name, '/');
263         $parts = explode('/', $name);
264         $level = 0;
265         foreach ($parts as $part) {
266             if ('..' === $part) {
267                 --$level;
268             } elseif ('.' !== $part) {
269                 ++$level;
270             }
271
272             if ($level < 0) {
273                 throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
274             }
275         }
276     }
277
278     private function isAbsolutePath($file)
279     {
280         return strspn($file, '/\\', 0, 1)
281             || (strlen($file) > 3 && ctype_alpha($file[0])
282                 && ':' === substr($file, 1, 1)
283                 && strspn($file, '/\\', 2, 1)
284             )
285             || null !== parse_url($file, PHP_URL_SCHEME)
286         ;
287     }
288 }
289
290 class_alias('Twig_Loader_Filesystem', 'Twig\Loader\FilesystemLoader', false);