Commit | Line | Data |
---|---|---|
6855525e JL |
1 | <?php |
2 | // vim: set expandtab tabstop=4 shiftwidth=4: | |
3 | // This code that was derived from the original PHPLIB Template class | |
4 | // is copyright by Kristian Koehntopp, NetUSE AG and was released | |
5 | // under the LGPL. | |
6 | // | |
7 | // Authors: Kristian Koehntopp <kris@koehntopp.de> (original from PHPLIB) | |
8 | // Bjoern Schotte <bjoern@rent-a-phpwizard.de> (PEARification) | |
9 | // Martin Jansen <mj@php.net> (PEAR conformance) | |
10 | // | |
11 | ||
12 | //require_once "PEAR.php"; | |
13 | ||
14 | /** | |
15 | * Converted PHPLIB Template class | |
16 | * | |
17 | * For those who want to use PHPLIB's fine template class, | |
18 | * here's a PEAR conforming class with the original PHPLIB | |
19 | * template code from phplib-stable CVS. Original author | |
20 | * was Kristian Koehntopp <kris@koehntopp.de> | |
21 | * | |
22 | * @author Bjoern Schotte <bjoern@rent-a-phpwizard.de> | |
23 | * @author Martin Jansen <mj@php.net> (PEAR conformance) | |
24 | * @version 1.0 | |
25 | */ | |
26 | class Template_PHPLIB | |
27 | { | |
28 | /** | |
29 | * If set, echo assignments | |
30 | * @var bool | |
31 | */ | |
32 | var $debug = false; | |
33 | ||
34 | /** | |
35 | * $file[handle] = "filename"; | |
36 | * @var array | |
37 | */ | |
38 | var $file = array(); | |
39 | ||
40 | /** | |
41 | * fallback paths that should be defined in a child class | |
42 | * @var array | |
43 | */ | |
44 | var $file_fallbacks = array(); | |
45 | ||
46 | /** | |
47 | * Relative filenames are relative to this pathname | |
48 | * @var string | |
49 | */ | |
50 | var $root = ""; | |
51 | ||
52 | /* | |
53 | * $_varKeys[key] = "key" | |
54 | * @var array | |
55 | */ | |
56 | var $_varKeys = array(); | |
57 | ||
58 | /** | |
59 | * $_varVals[key] = "value"; | |
60 | * @var array | |
61 | */ | |
62 | var $_varVals = array(); | |
63 | ||
64 | /** | |
65 | * "remove" => remove undefined variables | |
66 | * "comment" => replace undefined variables with comments | |
67 | * "keep" => keep undefined variables | |
68 | * @var string | |
69 | */ | |
70 | var $unknowns = "remove"; | |
71 | ||
72 | /** | |
73 | * "yes" => halt, "report" => report error, continue, "no" => ignore error quietly | |
74 | * @var string | |
75 | */ | |
76 | var $haltOnError = "report"; | |
77 | ||
78 | /** | |
79 | * The last error message is retained here | |
80 | * @var string | |
81 | * @see halt | |
82 | */ | |
83 | var $_lastError = ""; | |
84 | ||
85 | ||
86 | /** | |
87 | * Constructor | |
88 | * | |
89 | * @access public | |
90 | * @param string template root directory | |
91 | * @param string how to handle unknown variables | |
92 | * @param array fallback paths | |
93 | */ | |
94 | function Template_PHPLIB($root = ".", $unknowns = "remove", $fallback="") | |
95 | { | |
96 | $this->setRoot($root); | |
97 | $this->setUnknowns($unknowns); | |
98 | if (is_array($fallback)) $this->file_fallbacks = $fallback; | |
99 | } | |
100 | ||
101 | /** | |
102 | * Sets the template directory | |
103 | * | |
104 | * @access public | |
105 | * @param string new template directory | |
106 | * @return bool | |
107 | */ | |
108 | function setRoot($root) | |
109 | { | |
110 | if (!is_dir($root)) { | |
111 | $this->halt("setRoot: $root is not a directory."); | |
112 | return false; | |
113 | } | |
114 | ||
115 | $this->root = $root; | |
116 | ||
117 | return true; | |
118 | } | |
119 | ||
120 | /** | |
121 | * What to do with unknown variables | |
122 | * | |
123 | * three possible values: | |
124 | * | |
125 | * - "remove" will remove unknown variables | |
126 | * (don't use this if you define CSS in your page) | |
127 | * - "comment" will replace undefined variables with comments | |
128 | * - "keep" will keep undefined variables as-is | |
129 | * | |
130 | * @access public | |
131 | * @param string unknowns | |
132 | */ | |
133 | function setUnknowns($unknowns = "keep") | |
134 | { | |
135 | $this->unknowns = $unknowns; | |
136 | } | |
137 | ||
138 | /** | |
139 | * Set appropriate template files | |
140 | * | |
141 | * With this method you set the template files you want to use. | |
142 | * Either you supply an associative array with key/value pairs | |
143 | * where the key is the handle for the filname and the value | |
144 | * is the filename itself, or you define $handle as the file name | |
145 | * handle and $filename as the filename if you want to define only | |
146 | * one template. | |
147 | * | |
148 | * @access public | |
149 | * @param mixed handle for a filename or array with handle/name value pairs | |
150 | * @param string name of template file | |
151 | * @return bool | |
152 | */ | |
153 | function setFile($handle, $filename = "") | |
154 | { | |
155 | if (!is_array($handle)) { | |
156 | ||
157 | if ($filename == "") { | |
158 | $this->halt("setFile: For handle $handle filename is empty."); | |
159 | return false; | |
160 | } | |
161 | ||
162 | $this->file[$handle] = $this->_filename($filename); | |
163 | ||
164 | } else { | |
165 | ||
166 | reset($handle); | |
167 | while (list($h, $f) = each($handle)) { | |
168 | $this->file[$h] = $this->_filename($f); | |
169 | } | |
170 | } | |
171 | } | |
172 | ||
173 | /** | |
174 | * Set a block in the appropriate template handle | |
175 | * | |
176 | * By setting a block like that: | |
177 | * | |
178 | * <!-- BEGIN blockname --> | |
179 | * html code | |
180 | * <!-- END blockname --> | |
181 | * | |
182 | * you can easily do repeating HTML code, i.e. output | |
183 | * database data nice formatted into a HTML table where | |
184 | * each DB row is placed into a HTML table row which is | |
185 | * defined in this block. | |
186 | * It extracts the template $handle from $parent and places | |
187 | * variable {$name} instead. | |
188 | * | |
189 | * @access public | |
190 | * @param string parent handle | |
191 | * @param string block name handle | |
192 | * @param string variable substitution name | |
193 | */ | |
194 | function setBlock($parent, $handle, $name = "") | |
195 | { | |
196 | if (!$this->_loadFile($parent)) { | |
197 | $this->halt("setBlock: unable to load $parent."); | |
198 | return false; | |
199 | } | |
200 | ||
201 | if ($name == "") { | |
202 | $name = $handle; | |
203 | } | |
204 | ||
205 | $str = $this->getVar($parent); | |
206 | $reg = "/[ \t]*<!--\s+BEGIN $handle\s+-->\s*?\n?(\s*.*?\n?)\s*<!--\s+END $handle\s+-->\s*?\n?/sm"; | |
207 | preg_match_all($reg, $str, $m); | |
208 | $str = preg_replace($reg, "{" . "$name}", $str); | |
209 | ||
210 | if (isset($m[1][0])) $this->setVar($handle, $m[1][0]); | |
211 | $this->setVar($parent, $str); | |
212 | } | |
213 | ||
214 | /** | |
215 | * Set corresponding substitutions for placeholders | |
216 | * | |
217 | * @access public | |
218 | * @param string name of a variable that is to be defined or an array of variables with value substitution as key/value pairs | |
219 | * @param string value of that variable | |
220 | * @param boolean if true, the value is appended to the variable's existing value | |
221 | */ | |
222 | function setVar($varname, $value = "", $append = false) | |
223 | { | |
224 | if (!is_array($varname)) { | |
225 | ||
226 | if (!empty($varname)) | |
227 | if ($this->debug) print "scalar: set *$varname* to *$value*<br>\n"; | |
228 | ||
229 | $this->_varKeys[$varname] = $this->_varname($varname); | |
230 | ($append) ? $this->_varVals[$varname] .= $value : $this->_varVals[$varname] = $value; | |
231 | ||
232 | } else { | |
233 | reset($varname); | |
234 | ||
235 | while (list($k, $v) = each($varname)) { | |
236 | if (!empty($k)) | |
237 | if ($this->debug) print "array: set *$k* to *$v*<br>\n"; | |
238 | ||
239 | $this->_varKeys[$k] = $this->_varname($k); | |
240 | ($append) ? $this->_varVals[$k] .= $v : $this->_varVals[$k] = $v; | |
241 | } | |
242 | } | |
243 | } | |
244 | ||
245 | /** | |
246 | * Substitute variables in handle $handle | |
247 | * | |
248 | * @access public | |
249 | * @param string name of handle | |
250 | * @return mixed string substituted content of handle | |
251 | */ | |
252 | function subst($handle) | |
253 | { | |
254 | if (!$this->_loadFile($handle)) { | |
255 | $this->halt("subst: unable to load $handle."); | |
256 | return false; | |
257 | } | |
258 | ||
259 | return @str_replace($this->_varKeys, $this->_varVals, $this->getVar($handle)); | |
260 | } | |
261 | ||
262 | /** | |
263 | * Same as subst but printing the result | |
264 | * | |
265 | * @access public | |
266 | * @brother subst | |
267 | * @param string handle of template | |
268 | * @return bool always false | |
269 | */ | |
270 | function pSubst($handle) | |
271 | { | |
272 | print $this->subst($handle); | |
273 | return false; | |
274 | } | |
275 | ||
276 | /** | |
277 | * Parse handle into target | |
278 | * | |
279 | * Parses handle $handle into $target, eventually | |
280 | * appending handle at $target if $append is defined | |
281 | * as TRUE. | |
282 | * | |
283 | * @access public | |
284 | * @param string target handle to parse into | |
285 | * @param string which handle should be parsed | |
286 | * @param boolean append it to $target or not? | |
287 | * @return string parsed handle | |
288 | */ | |
289 | function parse($target, $handle, $append = false) | |
290 | { | |
291 | if (!is_array($handle)) { | |
292 | $str = $this->subst($handle); | |
293 | ||
294 | ($append) ? $this->setVar($target, $this->getVar($target) . $str) : $this->setVar($target, $str); | |
295 | } else { | |
296 | reset($handle); | |
297 | ||
298 | while (list(, $h) = each($handle)) { | |
299 | $str = $this->subst($h); | |
300 | $this->setVar($target, $str); | |
301 | } | |
302 | } | |
303 | ||
304 | return $str; | |
305 | } | |
306 | ||
307 | /** | |
308 | * Same as parse, but printing it. | |
309 | * | |
310 | * @access public | |
311 | * @brother parse | |
312 | * @param string target to parse into | |
313 | * @param string handle which should be parsed | |
314 | * @param should $handle be appended to $target? | |
315 | * @return bool | |
316 | */ | |
317 | function pParse($target, $handle, $append = false) | |
318 | { | |
319 | print $this->finish($this->parse($target, $handle, $append)); | |
320 | return false; | |
321 | } | |
322 | ||
323 | /** | |
324 | * Return all defined variables and their values | |
325 | * | |
326 | * @access public | |
327 | * @return array with all defined variables and their values | |
328 | */ | |
329 | function getVars() | |
330 | { | |
331 | reset($this->_varKeys); | |
332 | ||
333 | while (list($k, ) = each($this->_varKeys)) { | |
334 | $result[$k] = $this->getVar($k); | |
335 | } | |
336 | ||
337 | return $result; | |
338 | } | |
339 | ||
340 | /** | |
341 | * Return one or more specific variable(s) with their values. | |
342 | * | |
343 | * @access public | |
344 | * @param mixed array with variable names or one variable name as a string | |
345 | * @return mixed array of variable names with their values or value of one specific variable | |
346 | */ | |
347 | function getVar($varname) | |
348 | { | |
349 | if (!is_array($varname)) { | |
350 | if (isset($this->_varVals[$varname])) { | |
351 | return $this->_varVals[$varname]; | |
352 | } else { | |
353 | return ""; | |
354 | } | |
355 | } else { | |
356 | reset($varname); | |
357 | ||
358 | while (list($k, ) = each($varname)) { | |
359 | $result[$k] = (isset($this->_varVals[$k])) ? $this->_varVals[$k] : ""; | |
360 | } | |
361 | ||
362 | return $result; | |
363 | } | |
364 | } | |
365 | ||
366 | /** | |
367 | * Get undefined values of a handle | |
368 | * | |
369 | * @access public | |
370 | * @param string handle name | |
371 | * @return mixed false if an error occured or the undefined values | |
372 | */ | |
373 | function getUndefined($handle) | |
374 | { | |
375 | if (!$this->_loadFile($handle)) { | |
376 | $this->halt("getUndefined: unable to load $handle."); | |
377 | return false; | |
378 | } | |
379 | ||
380 | preg_match_all("/{([^ \t\r\n}]+)}/", $this->getVar($handle), $m); | |
381 | $m = $m[1]; | |
382 | if (!is_array($m)) { | |
383 | return false; | |
384 | } | |
385 | ||
386 | reset($m); | |
387 | while (list(, $v) = each($m)) { | |
388 | if (!isset($this->_varKeys[$v])) { | |
389 | $result[$v] = $v; | |
390 | } | |
391 | } | |
392 | ||
393 | if (isset($result) && count($result)) { | |
394 | return $result; | |
395 | } else { | |
396 | return false; | |
397 | } | |
398 | } | |
399 | ||
400 | /** | |
401 | * Finish string | |
402 | * | |
403 | * @access public | |
404 | * @param string string to finish | |
405 | * @return finished, i.e. substituted string | |
406 | */ | |
407 | function finish($str) | |
408 | { | |
409 | switch ($this->unknowns) { | |
410 | case "remove": | |
411 | $str = preg_replace('/{[^ \t\r\n}]+}/', "", $str); | |
412 | break; | |
413 | ||
414 | case "comment": | |
415 | $str = preg_replace('/{([^ \t\r\n}]+)}/', "<!-- Template $handle: Variable \\1 undefined -->", $str); | |
416 | break; | |
417 | } | |
418 | ||
419 | return $str; | |
420 | } | |
421 | ||
422 | /** | |
423 | * Print variable to the browser | |
424 | * | |
425 | * @access public | |
426 | * @param string name of variable to print | |
427 | */ | |
428 | function p($varname) | |
429 | { | |
430 | print $this->finish($this->getVar($varname)); | |
431 | } | |
432 | ||
433 | /** | |
434 | * Get finished variable | |
435 | * | |
436 | * @access public public | |
437 | * @param string variable to get | |
438 | * @return string string with finished variable | |
439 | */ | |
440 | function get($varname) | |
441 | { | |
442 | return $this->finish($this->getVar($varname)); | |
443 | } | |
444 | ||
445 | /** | |
446 | * Complete filename | |
447 | * | |
448 | * Complete filename, i.e. testing it for slashes | |
449 | * | |
450 | * @access private | |
451 | * @param string filename to be completed | |
452 | * @return string completed filename | |
453 | */ | |
454 | function _filename($filename) | |
455 | { | |
456 | // if (substr($filename, 0, 1) != "/") { | |
457 | // $filename = $this->root."/".$filename; | |
458 | // } | |
459 | ||
460 | if (file_exists($filename)) return $filename; | |
461 | if (is_array($this->file_fallbacks) && count($this->file_fallbacks) > 0) { | |
462 | reset($this->file_fallbacks); | |
463 | while (list(,$v) = each($this->file_fallbacks)) { | |
464 | if (file_exists($v.basename($filename))) return $v.basename($filename); | |
465 | } | |
466 | $this->halt(sprintf("filename: file %s does not exist in the fallback paths %s.",$filename,implode(",",$this->file_fallbacks))); | |
467 | return false; | |
468 | } else { | |
469 | $this->halt(sprintf("filename: file %s does not exist.",$filename)); | |
470 | return false; | |
471 | } | |
472 | ||
473 | return $filename; | |
474 | } | |
475 | ||
476 | /** | |
477 | * Protect a replacement variable | |
478 | * | |
479 | * @access private | |
480 | * @param string name of replacement variable | |
481 | * @return string replaced variable | |
482 | */ | |
483 | function _varname($varname) | |
484 | { | |
485 | return "{".$varname."}"; | |
486 | } | |
487 | ||
488 | /** | |
489 | * load file defined by handle if it is not loaded yet | |
490 | * | |
491 | * @access private | |
492 | * @param string handle | |
493 | * @return bool FALSE if error, true if all is ok | |
494 | */ | |
495 | function _loadFile($handle) | |
496 | { | |
497 | if (isset($this->_varKeys[$handle]) and !empty($this->_varVals[$handle])) { | |
498 | return true; | |
499 | } | |
500 | ||
501 | if (!isset($this->file[$handle])) { | |
502 | $this->halt("loadfile: $handle is not a valid handle."); | |
503 | return false; | |
504 | } | |
505 | ||
506 | $filename = $this->file[$handle]; | |
507 | if (function_exists("file_get_contents")) { | |
508 | $str = file_get_contents($filename); | |
509 | } else { | |
510 | if (!$fp = @fopen($filename,"r")) { | |
511 | $this->halt("loadfile: couldn't open $filename"); | |
512 | return false; | |
513 | } | |
514 | ||
515 | $str = fread($fp,filesize($filename)); | |
516 | fclose($fp); | |
517 | } | |
518 | ||
519 | if ($str=='') { | |
520 | $this->halt("loadfile: While loading $handle, $filename does not exist or is empty."); | |
521 | return false; | |
522 | } | |
523 | ||
524 | $this->setVar($handle, $str); | |
525 | ||
526 | return true; | |
527 | } | |
528 | ||
529 | /** | |
530 | * Error function. Halt template system with message to show | |
531 | * | |
532 | * @access public | |
533 | * @param string message to show | |
534 | * @return bool | |
535 | */ | |
536 | function halt($msg) | |
537 | { | |
538 | $this->_lastError = $msg; | |
539 | ||
540 | if ($this->haltOnError != "no") { | |
541 | // return $this->haltMsg($msg); | |
542 | $this->haltMsg($msg); | |
543 | } | |
544 | ||
545 | if ($this->haltOnError == "yes") { | |
546 | die("<b>Halted.</b>"); | |
547 | } | |
548 | ||
549 | return false; | |
550 | } | |
551 | ||
552 | /** | |
553 | * printf error message to show | |
554 | * | |
555 | * @access public | |
556 | * @param string message to show | |
557 | * @return object PEAR error object | |
558 | */ | |
559 | function haltMsg($msg) | |
560 | { | |
561 | // PEAR::raiseError(sprintf("<b>Template Error:</b> %s<br>\n", $msg)); | |
562 | printf("<b>Template Error:</b> %s<br>\n", $msg); | |
563 | } | |
564 | } | |
565 | ?> |