Verzeichnisstruktur phpBB-3.2.0
- Veröffentlicht
- 06.01.2017
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
Template.php
001 <?php
002
003 /*
004 * This file is part of Twig.
005 *
006 * (c) 2009 Fabien Potencier
007 * (c) 2009 Armin Ronacher
008 *
009 * For the full copyright and license information, please view the LICENSE
010 * file that was distributed with this source code.
011 */
012
013 /**
014 * Default base class for compiled templates.
015 *
016 * @author Fabien Potencier <fabien@symfony.com>
017 */
018 abstract class Twig_Template implements Twig_TemplateInterface
019 {
020 protected static $cache = array();
021
022 protected $parent;
023 protected $parents = array();
024 protected $env;
025 protected $blocks = array();
026 protected $traits = array();
027
028 /**
029 * Constructor.
030 *
031 * @param Twig_Environment $env A Twig_Environment instance
032 */
033 public function __construct(Twig_Environment $env)
034 {
035 $this->env = $env;
036 }
037
038 /**
039 * Returns the template name.
040 *
041 * @return string The template name
042 */
043 abstract public function getTemplateName();
044
045 /**
046 * @deprecated since 1.20 (to be removed in 2.0)
047 */
048 public function getEnvironment()
049 {
050 @trigger_error('The '.__METHOD__.' method is deprecated since version 1.20 and will be removed in 2.0.', E_USER_DEPRECATED);
051
052 return $this->env;
053 }
054
055 /**
056 * Returns the parent template.
057 *
058 * This method is for internal use only and should never be called
059 * directly.
060 *
061 * @param array $context
062 *
063 * @return Twig_TemplateInterface|false The parent template or false if there is no parent
064 *
065 * @internal
066 */
067 public function getParent(array $context)
068 {
069 if (null !== $this->parent) {
070 return $this->parent;
071 }
072
073 try {
074 $parent = $this->doGetParent($context);
075
076 if (false === $parent) {
077 return false;
078 }
079
080 if ($parent instanceof self) {
081 return $this->parents[$parent->getTemplateName()] = $parent;
082 }
083
084 if (!isset($this->parents[$parent])) {
085 $this->parents[$parent] = $this->loadTemplate($parent);
086 }
087 } catch (Twig_Error_Loader $e) {
088 $e->setTemplateFile(null);
089 $e->guess();
090
091 throw $e;
092 }
093
094 return $this->parents[$parent];
095 }
096
097 protected function doGetParent(array $context)
098 {
099 return false;
100 }
101
102 public function isTraitable()
103 {
104 return true;
105 }
106
107 /**
108 * Displays a parent block.
109 *
110 * This method is for internal use only and should never be called
111 * directly.
112 *
113 * @param string $name The block name to display from the parent
114 * @param array $context The context
115 * @param array $blocks The current set of blocks
116 *
117 * @internal
118 */
119 public function displayParentBlock($name, array $context, array $blocks = array())
120 {
121 $name = (string) $name;
122
123 if (isset($this->traits[$name])) {
124 $this->traits[$name][0]->displayBlock($name, $context, $blocks, false);
125 } elseif (false !== $parent = $this->getParent($context)) {
126 $parent->displayBlock($name, $context, $blocks, false);
127 } else {
128 throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block', $name), -1, $this->getTemplateName());
129 }
130 }
131
132 /**
133 * Displays a block.
134 *
135 * This method is for internal use only and should never be called
136 * directly.
137 *
138 * @param string $name The block name to display
139 * @param array $context The context
140 * @param array $blocks The current set of blocks
141 * @param bool $useBlocks Whether to use the current set of blocks
142 *
143 * @internal
144 */
145 public function displayBlock($name, array $context, array $blocks = array(), $useBlocks = true)
146 {
147 $name = (string) $name;
148
149 if ($useBlocks && isset($blocks[$name])) {
150 $template = $blocks[$name][0];
151 $block = $blocks[$name][1];
152 } elseif (isset($this->blocks[$name])) {
153 $template = $this->blocks[$name][0];
154 $block = $this->blocks[$name][1];
155 } else {
156 $template = null;
157 $block = null;
158 }
159
160 if (null !== $template) {
161 // avoid RCEs when sandbox is enabled
162 if (!$template instanceof self) {
163 throw new LogicException('A block must be a method on a Twig_Template instance.');
164 }
165
166 try {
167 $template->$block($context, $blocks);
168 } catch (Twig_Error $e) {
169 if (!$e->getTemplateFile()) {
170 $e->setTemplateFile($template->getTemplateName());
171 }
172
173 // this is mostly useful for Twig_Error_Loader exceptions
174 // see Twig_Error_Loader
175 if (false === $e->getTemplateLine()) {
176 $e->setTemplateLine(-1);
177 $e->guess();
178 }
179
180 throw $e;
181 } catch (Exception $e) {
182 throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getTemplateName(), $e);
183 }
184 } elseif (false !== $parent = $this->getParent($context)) {
185 $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false);
186 }
187 }
188
189 /**
190 * Renders a parent block.
191 *
192 * This method is for internal use only and should never be called
193 * directly.
194 *
195 * @param string $name The block name to render from the parent
196 * @param array $context The context
197 * @param array $blocks The current set of blocks
198 *
199 * @return string The rendered block
200 *
201 * @internal
202 */
203 public function renderParentBlock($name, array $context, array $blocks = array())
204 {
205 ob_start();
206 $this->displayParentBlock($name, $context, $blocks);
207
208 return ob_get_clean();
209 }
210
211 /**
212 * Renders a block.
213 *
214 * This method is for internal use only and should never be called
215 * directly.
216 *
217 * @param string $name The block name to render
218 * @param array $context The context
219 * @param array $blocks The current set of blocks
220 * @param bool $useBlocks Whether to use the current set of blocks
221 *
222 * @return string The rendered block
223 *
224 * @internal
225 */
226 public function renderBlock($name, array $context, array $blocks = array(), $useBlocks = true)
227 {
228 ob_start();
229 $this->displayBlock($name, $context, $blocks, $useBlocks);
230
231 return ob_get_clean();
232 }
233
234 /**
235 * Returns whether a block exists or not.
236 *
237 * This method is for internal use only and should never be called
238 * directly.
239 *
240 * This method does only return blocks defined in the current template
241 * or defined in "used" traits.
242 *
243 * It does not return blocks from parent templates as the parent
244 * template name can be dynamic, which is only known based on the
245 * current context.
246 *
247 * @param string $name The block name
248 *
249 * @return bool true if the block exists, false otherwise
250 *
251 * @internal
252 */
253 public function hasBlock($name)
254 {
255 return isset($this->blocks[(string) $name]);
256 }
257
258 /**
259 * Returns all block names.
260 *
261 * This method is for internal use only and should never be called
262 * directly.
263 *
264 * @return array An array of block names
265 *
266 * @see hasBlock
267 *
268 * @internal
269 */
270 public function getBlockNames()
271 {
272 return array_keys($this->blocks);
273 }
274
275 protected function loadTemplate($template, $templateName = null, $line = null, $index = null)
276 {
277 try {
278 if (is_array($template)) {
279 return $this->env->resolveTemplate($template);
280 }
281
282 if ($template instanceof self) {
283 return $template;
284 }
285
286 return $this->env->loadTemplate($template, $index);
287 } catch (Twig_Error $e) {
288 if (!$e->getTemplateFile()) {
289 $e->setTemplateFile($templateName ? $templateName : $this->getTemplateName());
290 }
291
292 if ($e->getTemplateLine()) {
293 throw $e;
294 }
295
296 if (!$line) {
297 $e->guess();
298 } else {
299 $e->setTemplateLine($line);
300 }
301
302 throw $e;
303 }
304 }
305
306 /**
307 * Returns all blocks.
308 *
309 * This method is for internal use only and should never be called
310 * directly.
311 *
312 * @return array An array of blocks
313 *
314 * @see hasBlock
315 *
316 * @internal
317 */
318 public function getBlocks()
319 {
320 return $this->blocks;
321 }
322
323 /**
324 * Returns the template source code.
325 *
326 * @return string|null The template source code or null if it is not available
327 */
328 public function getSource()
329 {
330 $reflector = new ReflectionClass($this);
331 $file = $reflector->getFileName();
332
333 if (!file_exists($file)) {
334 return;
335 }
336
337 $source = file($file, FILE_IGNORE_NEW_LINES);
338 array_splice($source, 0, $reflector->getEndLine());
339
340 $i = 0;
341 while (isset($source[$i]) && '/* */' === substr_replace($source[$i], '', 3, -2)) {
342 $source[$i] = str_replace('*//* ', '*/', substr($source[$i], 3, -2));
343 ++$i;
344 }
345 array_splice($source, $i);
346
347 return implode("\n", $source);
348 }
349
350 /**
351 * {@inheritdoc}
352 */
353 public function display(array $context, array $blocks = array())
354 {
355 $this->displayWithErrorHandling($this->env->mergeGlobals($context), array_merge($this->blocks, $blocks));
356 }
357
358 /**
359 * {@inheritdoc}
360 */
361 public function render(array $context)
362 {
363 $level = ob_get_level();
364 ob_start();
365 try {
366 $this->display($context);
367 } catch (Exception $e) {
368 while (ob_get_level() > $level) {
369 ob_end_clean();
370 }
371
372 throw $e;
373 } catch (Throwable $e) {
374 while (ob_get_level() > $level) {
375 ob_end_clean();
376 }
377
378 throw $e;
379 }
380
381 return ob_get_clean();
382 }
383
384 protected function displayWithErrorHandling(array $context, array $blocks = array())
385 {
386 try {
387 $this->doDisplay($context, $blocks);
388 } catch (Twig_Error $e) {
389 if (!$e->getTemplateFile()) {
390 $e->setTemplateFile($this->getTemplateName());
391 }
392
393 // this is mostly useful for Twig_Error_Loader exceptions
394 // see Twig_Error_Loader
395 if (false === $e->getTemplateLine()) {
396 $e->setTemplateLine(-1);
397 $e->guess();
398 }
399
400 throw $e;
401 } catch (Exception $e) {
402 throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getTemplateName(), $e);
403 }
404 }
405
406 /**
407 * Auto-generated method to display the template with the given context.
408 *
409 * @param array $context An array of parameters to pass to the template
410 * @param array $blocks An array of blocks to pass to the template
411 */
412 abstract protected function doDisplay(array $context, array $blocks = array());
413
414 /**
415 * Returns a variable from the context.
416 *
417 * This method is for internal use only and should never be called
418 * directly.
419 *
420 * This method should not be overridden in a sub-class as this is an
421 * implementation detail that has been introduced to optimize variable
422 * access for versions of PHP before 5.4. This is not a way to override
423 * the way to get a variable value.
424 *
425 * @param array $context The context
426 * @param string $item The variable to return from the context
427 * @param bool $ignoreStrictCheck Whether to ignore the strict variable check or not
428 *
429 * @return mixed The content of the context variable
430 *
431 * @throws Twig_Error_Runtime if the variable does not exist and Twig is running in strict mode
432 *
433 * @internal
434 */
435 final protected function getContext($context, $item, $ignoreStrictCheck = false)
436 {
437 if (!array_key_exists($item, $context)) {
438 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
439 return;
440 }
441
442 throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist', $item), -1, $this->getTemplateName());
443 }
444
445 return $context[$item];
446 }
447
448 /**
449 * Returns the attribute value for a given array/object.
450 *
451 * @param mixed $object The object or array from where to get the item
452 * @param mixed $item The item to get from the array or object
453 * @param array $arguments An array of arguments to pass if the item is an object method
454 * @param string $type The type of attribute (@see Twig_Template constants)
455 * @param bool $isDefinedTest Whether this is only a defined check
456 * @param bool $ignoreStrictCheck Whether to ignore the strict attribute check or not
457 *
458 * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true
459 *
460 * @throws Twig_Error_Runtime if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false
461 */
462 protected function getAttribute($object, $item, array $arguments = array(), $type = self::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
463 {
464 // array
465 if (self::METHOD_CALL !== $type) {
466 $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item;
467
468 if ((is_array($object) && array_key_exists($arrayItem, $object))
469 || ($object instanceof ArrayAccess && isset($object[$arrayItem]))
470 ) {
471 if ($isDefinedTest) {
472 return true;
473 }
474
475 return $object[$arrayItem];
476 }
477
478 if (self::ARRAY_CALL === $type || !is_object($object)) {
479 if ($isDefinedTest) {
480 return false;
481 }
482
483 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
484 return;
485 }
486
487 if ($object instanceof ArrayAccess) {
488 $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist', $arrayItem, get_class($object));
489 } elseif (is_object($object)) {
490 $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface', $item, get_class($object));
491 } elseif (is_array($object)) {
492 if (empty($object)) {
493 $message = sprintf('Key "%s" does not exist as the array is empty', $arrayItem);
494 } else {
495 $message = sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object)));
496 }
497 } elseif (self::ARRAY_CALL === $type) {
498 if (null === $object) {
499 $message = sprintf('Impossible to access a key ("%s") on a null variable', $item);
500 } else {
501 $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
502 }
503 } elseif (null === $object) {
504 $message = sprintf('Impossible to access an attribute ("%s") on a null variable', $item);
505 } else {
506 $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
507 }
508
509 throw new Twig_Error_Runtime($message, -1, $this->getTemplateName());
510 }
511 }
512
513 if (!is_object($object)) {
514 if ($isDefinedTest) {
515 return false;
516 }
517
518 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
519 return;
520 }
521
522 if (null === $object) {
523 $message = sprintf('Impossible to invoke a method ("%s") on a null variable', $item);
524 } else {
525 $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
526 }
527
528 throw new Twig_Error_Runtime($message, -1, $this->getTemplateName());
529 }
530
531 // object property
532 if (self::METHOD_CALL !== $type && !$object instanceof self) { // Twig_Template does not have public properties, and we don't want to allow access to internal ones
533 if (isset($object->$item) || array_key_exists((string) $item, $object)) {
534 if ($isDefinedTest) {
535 return true;
536 }
537
538 if ($this->env->hasExtension('sandbox')) {
539 $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
540 }
541
542 return $object->$item;
543 }
544 }
545
546 $class = get_class($object);
547
548 // object method
549 if (!isset(self::$cache[$class]['methods'])) {
550 // get_class_methods returns all methods accessible in the scope, but we only want public ones to be accessible in templates
551 if ($object instanceof self) {
552 $ref = new ReflectionClass($class);
553 $methods = array();
554
555 foreach ($ref->getMethods(ReflectionMethod::IS_PUBLIC) as $refMethod) {
556 $methodName = strtolower($refMethod->name);
557
558 // Accessing the environment from templates is forbidden to prevent untrusted changes to the environment
559 if ('getenvironment' !== $methodName) {
560 $methods[$methodName] = true;
561 }
562 }
563
564 self::$cache[$class]['methods'] = $methods;
565 } else {
566 self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
567 }
568 }
569
570 $call = false;
571 $lcItem = strtolower($item);
572 if (isset(self::$cache[$class]['methods'][$lcItem])) {
573 $method = (string) $item;
574 } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
575 $method = 'get'.$item;
576 } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
577 $method = 'is'.$item;
578 } elseif (isset(self::$cache[$class]['methods']['__call'])) {
579 $method = (string) $item;
580 $call = true;
581 } else {
582 if ($isDefinedTest) {
583 return false;
584 }
585
586 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
587 return;
588 }
589
590 throw new Twig_Error_Runtime(sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()" or "__call()" exist and have public access in class "%2$s"', $item, get_class($object)), -1, $this->getTemplateName());
591 }
592
593 if ($isDefinedTest) {
594 return true;
595 }
596
597 if ($this->env->hasExtension('sandbox')) {
598 $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method);
599 }
600
601 // Some objects throw exceptions when they have __call, and the method we try
602 // to call is not supported. If ignoreStrictCheck is true, we should return null.
603 try {
604 $ret = call_user_func_array(array($object, $method), $arguments);
605 } catch (BadMethodCallException $e) {
606 if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) {
607 return;
608 }
609 throw $e;
610 }
611
612 // useful when calling a template method from a template
613 // this is not supported but unfortunately heavily used in the Symfony profiler
614 if ($object instanceof Twig_TemplateInterface) {
615 return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
616 }
617
618 return $ret;
619 }
620 }
621