/twig/lib/Twig/Loader/Filesystem.php

https://bitbucket.org/j3z/checklist-generator · PHP · 223 lines · 121 code · 33 blank · 69 comment · 17 complexity · 918f9066fa54d9ec1691ab64ae67942c MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of Twig.
  4. *
  5. * (c) 2009 Fabien Potencier
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. /**
  11. * Loads template from the filesystem.
  12. *
  13. * @author Fabien Potencier <fabien@symfony.com>
  14. */
  15. class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
  16. {
  17. protected $paths;
  18. protected $cache;
  19. /**
  20. * Constructor.
  21. *
  22. * @param string|array $paths A path or an array of paths where to look for templates
  23. */
  24. public function __construct($paths = array())
  25. {
  26. if ($paths) {
  27. $this->setPaths($paths);
  28. }
  29. }
  30. /**
  31. * Returns the paths to the templates.
  32. *
  33. * @param string $namespace A path namespace
  34. *
  35. * @return array The array of paths where to look for templates
  36. */
  37. public function getPaths($namespace = '__main__')
  38. {
  39. return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array();
  40. }
  41. /**
  42. * Returns the path namespaces.
  43. *
  44. * The "__main__" namespace is always defined.
  45. *
  46. * @return array The array of defined namespaces
  47. */
  48. public function getNamespaces()
  49. {
  50. return array_keys($this->paths);
  51. }
  52. /**
  53. * Sets the paths where templates are stored.
  54. *
  55. * @param string|array $paths A path or an array of paths where to look for templates
  56. * @param string $namespace A path namespace
  57. */
  58. public function setPaths($paths, $namespace = '__main__')
  59. {
  60. if (!is_array($paths)) {
  61. $paths = array($paths);
  62. }
  63. $this->paths[$namespace] = array();
  64. foreach ($paths as $path) {
  65. $this->addPath($path, $namespace);
  66. }
  67. }
  68. /**
  69. * Adds a path where templates are stored.
  70. *
  71. * @param string $path A path where to look for templates
  72. * @param string $namespace A path name
  73. *
  74. * @throws Twig_Error_Loader
  75. */
  76. public function addPath($path, $namespace = '__main__')
  77. {
  78. // invalidate the cache
  79. $this->cache = array();
  80. if (!is_dir($path)) {
  81. throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
  82. }
  83. $this->paths[$namespace][] = rtrim($path, '/\\');
  84. }
  85. /**
  86. * Prepends a path where templates are stored.
  87. *
  88. * @param string $path A path where to look for templates
  89. * @param string $namespace A path name
  90. *
  91. * @throws Twig_Error_Loader
  92. */
  93. public function prependPath($path, $namespace = '__main__')
  94. {
  95. // invalidate the cache
  96. $this->cache = array();
  97. if (!is_dir($path)) {
  98. throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
  99. }
  100. $path = rtrim($path, '/\\');
  101. if (!isset($this->paths[$namespace])) {
  102. $this->paths[$namespace][] = $path;
  103. } else {
  104. array_unshift($this->paths[$namespace], $path);
  105. }
  106. }
  107. /**
  108. * {@inheritdoc}
  109. */
  110. public function getSource($name)
  111. {
  112. return file_get_contents($this->findTemplate($name));
  113. }
  114. /**
  115. * {@inheritdoc}
  116. */
  117. public function getCacheKey($name)
  118. {
  119. return $this->findTemplate($name);
  120. }
  121. /**
  122. * {@inheritdoc}
  123. */
  124. public function exists($name)
  125. {
  126. $name = (string) $name;
  127. if (isset($this->cache[$name])) {
  128. return true;
  129. }
  130. try {
  131. $this->findTemplate($name);
  132. return true;
  133. } catch (Twig_Error_Loader $exception) {
  134. return false;
  135. }
  136. }
  137. /**
  138. * {@inheritdoc}
  139. */
  140. public function isFresh($name, $time)
  141. {
  142. return filemtime($this->findTemplate($name)) <= $time;
  143. }
  144. protected function findTemplate($name)
  145. {
  146. $name = (string) $name;
  147. // normalize name
  148. $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/'));
  149. if (isset($this->cache[$name])) {
  150. return $this->cache[$name];
  151. }
  152. $this->validateName($name);
  153. $namespace = '__main__';
  154. if (isset($name[0]) && '@' == $name[0]) {
  155. if (false === $pos = strpos($name, '/')) {
  156. throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
  157. }
  158. $namespace = substr($name, 1, $pos - 1);
  159. $name = substr($name, $pos + 1);
  160. }
  161. if (!isset($this->paths[$namespace])) {
  162. throw new Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace));
  163. }
  164. foreach ($this->paths[$namespace] as $path) {
  165. if (is_file($path.'/'.$name)) {
  166. return $this->cache[$name] = $path.'/'.$name;
  167. }
  168. }
  169. throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace])));
  170. }
  171. protected function validateName($name)
  172. {
  173. if (false !== strpos($name, "\0")) {
  174. throw new Twig_Error_Loader('A template name cannot contain NUL bytes.');
  175. }
  176. $name = ltrim($name, '/');
  177. $parts = explode('/', $name);
  178. $level = 0;
  179. foreach ($parts as $part) {
  180. if ('..' === $part) {
  181. --$level;
  182. } elseif ('.' !== $part) {
  183. ++$level;
  184. }
  185. if ($level < 0) {
  186. throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
  187. }
  188. }
  189. }
  190. }