1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Latte\Loaders;
9:
10: use Latte;
11:
12:
13: 14: 15:
16: class FileLoader implements Latte\ILoader
17: {
18: use Latte\Strict;
19:
20:
21: private $baseDir;
22:
23:
24: public function __construct($baseDir = null)
25: {
26: $this->baseDir = $baseDir ? $this->normalizePath("$baseDir/") : null;
27: }
28:
29:
30: 31: 32: 33:
34: public function getContent($fileName)
35: {
36: $file = $this->baseDir . $fileName;
37: if ($this->baseDir && !Latte\Helpers::startsWith($this->normalizePath($file), $this->baseDir)) {
38: throw new \RuntimeException("Template '$file' is not within the allowed path '$this->baseDir'.");
39:
40: } elseif (!is_file($file)) {
41: throw new \RuntimeException("Missing template file '$file'.");
42:
43: } elseif ($this->isExpired($fileName, time())) {
44: if (@touch($file) === false) {
45: trigger_error("File's modification time is in the future. Cannot update it: " . error_get_last()['message'], E_USER_WARNING);
46: }
47: }
48: return file_get_contents($file);
49: }
50:
51:
52: 53: 54:
55: public function isExpired($file, $time)
56: {
57: return @filemtime($this->baseDir . $file) > $time;
58: }
59:
60:
61: 62: 63: 64:
65: public function getReferredName($file, $referringFile)
66: {
67: if ($this->baseDir || !preg_match('#/|\\\\|[a-z][a-z0-9+.-]*:#iA', $file)) {
68: $file = $this->normalizePath($referringFile . '/../' . $file);
69: }
70: return $file;
71: }
72:
73:
74: 75: 76: 77:
78: public function getUniqueId($file)
79: {
80: return $this->baseDir . strtr($file, '/', DIRECTORY_SEPARATOR);
81: }
82:
83:
84: 85: 86:
87: private static function normalizePath($path)
88: {
89: $res = [];
90: foreach (explode('/', strtr($path, '\\', '/')) as $part) {
91: if ($part === '..' && $res && end($res) !== '..') {
92: array_pop($res);
93: } elseif ($part !== '.') {
94: $res[] = $part;
95: }
96: }
97: return implode(DIRECTORY_SEPARATOR, $res);
98: }
99: }
100: