1 : <?php
2 :
3 : /**
4 : * represents a Dwoo template contained in a file
5 : *
6 : * This software is provided 'as-is', without any express or implied warranty.
7 : * In no event will the authors be held liable for any damages arising from the use of this software.
8 : *
9 : * @author Jordi Boggiano <j.boggiano@seld.be>
10 : * @copyright Copyright (c) 2008, Jordi Boggiano
11 : * @license http://dwoo.org/LICENSE Modified BSD License
12 : * @link http://dwoo.org/
13 : * @version 1.1.0
14 : * @date 2009-07-18
15 : * @package Dwoo
16 : */
17 : class Dwoo_Template_File extends Dwoo_Template_String
18 1 : {
19 : /**
20 : * template filename
21 : *
22 : * @var string
23 : */
24 : protected $file;
25 :
26 : /**
27 : * include path(s) to look into to find this template
28 : *
29 : * @var array
30 : */
31 : protected $includePath = null;
32 :
33 : /**
34 : * resolved path cache when looking for a file in multiple include paths
35 : *
36 : * this is reset when the include path is changed
37 : *
38 : * @var string
39 : */
40 : protected $resolvedPath = null;
41 :
42 : /**
43 : * creates a template from a file
44 : *
45 : * @param string $file the path to the template file, make sure it exists
46 : * @param int $cacheTime duration of the cache validity for this template,
47 : * if null it defaults to the Dwoo instance that will
48 : * render this template
49 : * @param string $cacheId the unique cache identifier of this page or anything else that
50 : * makes this template's content unique, if null it defaults
51 : * to the current url
52 : * @param string $compileId the unique compiled identifier, which is used to distinguish this
53 : * template from others, if null it defaults to the filename+bits of the path
54 : * @param mixed $includePath a string for a single path to look into for the given file, or an array of paths
55 : */
56 : public function __construct($file, $cacheTime = null, $cacheId = null, $compileId = null, $includePath = null)
57 : {
58 16 : $this->file = $file;
59 16 : $this->name = basename($file);
60 16 : $this->cacheTime = $cacheTime;
61 :
62 16 : if ($compileId !== null) {
63 0 : $this->compileId = str_replace('../', '__', strtr($compileId, '\\%?=!:;'.PATH_SEPARATOR, '/-------'));
64 0 : }
65 :
66 16 : if ($cacheId !== null) {
67 0 : $this->cacheId = str_replace('../', '__', strtr($cacheId, '\\%?=!:;'.PATH_SEPARATOR, '/-------'));
68 0 : }
69 :
70 16 : if (is_string($includePath)) {
71 2 : $this->includePath = array($includePath);
72 16 : } elseif (is_array($includePath)) {
73 0 : $this->includePath = $includePath;
74 0 : }
75 16 : }
76 :
77 : /**
78 : * sets the include path(s) to where the given template filename must be looked up
79 : *
80 : * @param mixed $paths the path to look into, can be string for a single path or an array of paths
81 : */
82 : public function setIncludePath($paths)
83 : {
84 1 : if (is_array($paths) === false) {
85 1 : $paths = array($paths);
86 1 : }
87 :
88 1 : $this->includePath = $paths;
89 1 : $this->resolvedPath = null;
90 1 : }
91 :
92 : /**
93 : * return the current include path(s)
94 : *
95 : * @return array
96 : */
97 : public function getIncludePath()
98 : {
99 6 : return $this->includePath;
100 : }
101 :
102 : /**
103 : * Checks if compiled file is valid (exists and it's the modification is greater or
104 : * equal to the modification time of the template file)
105 : *
106 : * @param string file
107 : * @return boolean True cache file existance and it's modification time
108 : */
109 : protected function isValidCompiledFile($file) {
110 3 : return parent::isValidCompiledFile($file) && (int)$this->getUid() <= filemtime($file);
111 : }
112 :
113 : /**
114 : * returns the template source of this template
115 : *
116 : * @return string
117 : */
118 : public function getSource()
119 : {
120 13 : return file_get_contents($this->getResourceIdentifier());
121 : }
122 :
123 : /**
124 : * returns the resource name for this template class
125 : *
126 : * @return string
127 : */
128 : public function getResourceName()
129 : {
130 9 : return 'file';
131 : }
132 :
133 : /**
134 : * returns this template's source filename
135 : *
136 : * @return string
137 : */
138 : public function getResourceIdentifier()
139 : {
140 15 : if ($this->resolvedPath !== null) {
141 1 : return $this->resolvedPath;
142 15 : } elseif ($this->includePath === null) {
143 14 : return $this->file;
144 : } else {
145 2 : foreach ($this->includePath as $path) {
146 2 : $path = rtrim($path, DIRECTORY_SEPARATOR);
147 2 : if (file_exists($path.DIRECTORY_SEPARATOR.$this->file) === true) {
148 2 : $this->resolvedPath = $path . DIRECTORY_SEPARATOR . $this->file;
149 2 : return $this->resolvedPath;
150 : }
151 0 : }
152 :
153 0 : throw new Dwoo_Exception('Template "'.$this->file.'" could not be found in any of your include path(s)');
154 : }
155 : }
156 :
157 : /**
158 : * returns an unique value identifying the current version of this template,
159 : * in this case it's the unix timestamp of the last modification
160 : *
161 : * @return string
162 : */
163 : public function getUid()
164 : {
165 6 : return (string) filemtime($this->getResourceIdentifier());
166 : }
167 :
168 : /**
169 : * returns a new template object from the given include name, null if no include is
170 : * possible (resource not found), or false if include is not permitted by this resource type
171 : *
172 : * @param Dwoo $dwoo the dwoo instance requiring it
173 : * @param mixed $resourceId the filename (relative to this template's dir) of the template to include
174 : * @param int $cacheTime duration of the cache validity for this template,
175 : * if null it defaults to the Dwoo instance that will
176 : * render this template
177 : * @param string $cacheId the unique cache identifier of this page or anything else that
178 : * makes this template's content unique, if null it defaults
179 : * to the current url
180 : * @param string $compileId the unique compiled identifier, which is used to distinguish this
181 : * template from others, if null it defaults to the filename+bits of the path
182 : * @param Dwoo_ITemplate $parentTemplate the template that is requesting a new template object (through
183 : * an include, extends or any other plugin)
184 : * @return Dwoo_Template_File|null
185 : */
186 : public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null)
187 : {
188 9 : if (DIRECTORY_SEPARATOR === '\\') {
189 9 : $resourceId = str_replace(array("\t", "\n", "\r", "\f", "\v"), array('\\t', '\\n', '\\r', '\\f', '\\v'), $resourceId);
190 9 : }
191 9 : $resourceId = strtr($resourceId, '\\', '/');
192 :
193 9 : $includePath = null;
194 :
195 9 : if (file_exists($resourceId) === false) {
196 6 : if ($parentTemplate === null) {
197 3 : $parentTemplate = $dwoo->getTemplate();
198 3 : }
199 6 : if ($parentTemplate instanceof Dwoo_Template_File) {
200 6 : if ($includePath = $parentTemplate->getIncludePath()) {
201 0 : if (strstr($resourceId, '../')) {
202 0 : throw new Dwoo_Exception('When using an include path you can not reference a template into a parent directory (using ../)');
203 : }
204 0 : } else {
205 6 : $resourceId = dirname($parentTemplate->getResourceIdentifier()).DIRECTORY_SEPARATOR.$resourceId;
206 6 : if (file_exists($resourceId) === false) {
207 0 : return null;
208 : }
209 : }
210 6 : } else {
211 0 : return null;
212 : }
213 6 : }
214 :
215 9 : if ($policy = $dwoo->getSecurityPolicy()) {
216 0 : while (true) {
217 0 : if (preg_match('{^([a-z]+?)://}i', $resourceId)) {
218 0 : throw new Dwoo_Security_Exception('The security policy prevents you to read files from external sources : <em>'.$resourceId.'</em>.');
219 : }
220 :
221 0 : if ($includePath) {
222 0 : break;
223 : }
224 :
225 0 : $resourceId = realpath($resourceId);
226 0 : $dirs = $policy->getAllowedDirectories();
227 0 : foreach ($dirs as $dir=>$dummy) {
228 0 : if (strpos($resourceId, $dir) === 0) {
229 0 : break 2;
230 : }
231 0 : }
232 0 : throw new Dwoo_Security_Exception('The security policy prevents you to read <em>'.$resourceId.'</em>');
233 : }
234 0 : }
235 :
236 9 : $class = 'Dwoo_Template_File';
237 9 : if ($parentTemplate) {
238 6 : $class = get_class($parentTemplate);
239 6 : }
240 9 : return new $class($resourceId, $cacheTime, $cacheId, $compileId, $includePath);
241 : }
242 :
243 : /**
244 : * returns the full compiled file name and assigns a default value to it if
245 : * required
246 : *
247 : * @param Dwoo $dwoo the dwoo instance that requests the file name
248 : * @return string the full path to the compiled file
249 : */
250 : protected function getCompiledFilename(Dwoo $dwoo)
251 : {
252 : // no compile id was provided, set default
253 12 : if ($this->compileId===null) {
254 12 : $this->compileId = str_replace('../', '__', strtr($this->getResourceIdentifier(), '\\:', '/-'));
255 12 : }
256 12 : return $dwoo->getCompileDir() . $this->compileId.'.d'.Dwoo::RELEASE_TAG.'.php';
257 : }
258 :
259 : /**
260 : * returns some php code that will check if this template has been modified or not
261 : *
262 : * if the function returns null, the template will be instanciated and then the Uid checked
263 : *
264 : * @return string
265 : */
266 : public function getIsModifiedCode()
267 : {
268 6 : return '"'.$this->getUid().'" == filemtime('.var_export($this->getResourceIdentifier(), true).')';
269 : }
270 : }
|