PluginProbe
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor / 4.0.3
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor v4.0.3
4.0.3 4.0.2 4.0.1 4.0.0 3.16.6 3.16.5 3.16.4 3.16.3 3.16.2 3.16.1 3.16.0 3.15.9 3.9.9 3.9.5 3.9.6 3.9.7 3.9.8 1.1.7 1.1.8 1.1.9 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 341 releases
← All changes | assets/lib/Mustache/Engine.php +211 -130 2.0.24.0.3 View file →
@@ -2,9 +2,9 @@
2 2
3 3 /*
4 4 * This file is part of Mustache.php.
5 5 *
6 - * (c) 2012 Justin Hileman
6 + * (c) 2010-2017 Justin Hileman
7 7 *
8 8 * For the full copyright and license information, please view the LICENSE
9 9 * file that was distributed with this source code.
10 10 */
@@ -22,20 +22,30 @@
22 22 * @author Justin Hileman {@link http://justinhileman.com}
23 23 */
24 24 class Mustache_Engine
25 25 {
26 - const VERSION = '2.4.1';
27 - const SPEC_VERSION = '1.1.2';
26 + const VERSION = '2.14.2';
27 + const SPEC_VERSION = '1.2.2';
28 28
29 - const PRAGMA_FILTERS = 'FILTERS';
29 + const PRAGMA_FILTERS = 'FILTERS';
30 + const PRAGMA_BLOCKS = 'BLOCKS';
31 + const PRAGMA_ANCHORED_DOT = 'ANCHORED-DOT';
30 32
33 + // Known pragmas
34 + private static $knownPragmas = array(
35 + self::PRAGMA_FILTERS => true,
36 + self::PRAGMA_BLOCKS => true,
37 + self::PRAGMA_ANCHORED_DOT => true,
38 + );
39 +
31 40 // Template cache
32 41 private $templates = array();
33 42
34 43 // Environment
35 44 private $templateClassPrefix = '__Mustache_';
36 - private $cache = null;
37 - private $cacheFileMode = null;
45 + private $cache;
46 + private $lambdaCache;
47 + private $cacheLambdaTemplates = false;
38 48 private $loader;
39 49 private $partialsLoader;
40 50 private $helpers;
41 51 private $escape;
@@ -42,9 +52,16 @@
42 52 private $entityFlags = ENT_COMPAT;
43 53 private $charset = 'UTF-8';
44 54 private $logger;
45 55 private $strictCallables = false;
56 + private $pragmas = array();
57 + private $delimiters;
46 58
59 + // Services
60 + private $tokenizer;
61 + private $parser;
62 + private $compiler;
63 +
47 64 /**
48 65 * Mustache class constructor.
49 66 *
50 67 * Passing an $options array allows overriding certain Mustache options during instantiation:
@@ -52,9 +69,10 @@
52 69 * $options = array(
53 70 * // The class prefix for compiled templates. Defaults to '__Mustache_'.
54 71 * 'template_class_prefix' => '__MyTemplates_',
55 72 *
56 - * // A cache directory for compiled templates. Mustache will not cache templates unless this is set
73 + * // A Mustache cache instance or a cache directory string for compiled templates.
74 + * // Mustache will not cache templates unless this is set.
57 75 * 'cache' => dirname(__FILE__).'/tmp/cache/mustache',
58 76 *
59 77 * // Override default permissions for cache files. Defaults to using the system-defined umask. It is
60 78 * // *strongly* recommended that you configure your umask properly rather than overriding permissions here.
@@ -59,8 +77,20 @@
59 77 * // Override default permissions for cache files. Defaults to using the system-defined umask. It is
60 78 * // *strongly* recommended that you configure your umask properly rather than overriding permissions here.
61 79 * 'cache_file_mode' => 0666,
62 80 *
81 + * // Optionally, enable caching for lambda section templates. This is generally not recommended, as lambda
82 + * // sections are often too dynamic to benefit from caching.
83 + * 'cache_lambda_templates' => true,
84 + *
85 + * // Customize the tag delimiters used by this engine instance. Note that overriding here changes the
86 + * // delimiters used to parse all templates and partials loaded by this instance. To override just for a
87 + * // single template, use an inline "change delimiters" tag at the start of the template file:
88 + * //
89 + * // {{=<% %>=}}
90 + * //
91 + * 'delimiters' => '<% %>',
92 + *
63 93 * // A Mustache template loader instance. Uses a StringLoader if not specified.
64 94 * 'loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views'),
65 95 *
66 96 * // A Mustache loader instance for partials.
@@ -72,14 +102,14 @@
72 102 *
73 103 * // An array of 'helpers'. Helpers can be global variables or objects, closures (e.g. for higher order
74 104 * // sections), or any other valid Mustache context value. They will be prepended to the context stack,
75 105 * // so they will be available in any template loaded by this Mustache instance.
76 - * 'helpers' => array('i18n' => function($text) {
106 + * 'helpers' => array('i18n' => function ($text) {
77 107 * // do something translatey here...
78 108 * }),
79 109 *
80 110 * // An 'escape' callback, responsible for escaping double-mustache variables.
81 - * 'escape' => function($value) {
111 + * 'escape' => function ($value) {
82 112 * return htmlspecialchars($buffer, ENT_COMPAT, 'UTF-8');
83 113 * },
84 114 *
85 115 * // Type argument for `htmlspecialchars`. Defaults to ENT_COMPAT. You may prefer ENT_QUOTES.
@@ -98,11 +128,15 @@
98 128 * // "callable" in PHP, are not called to resolve variables for interpolation or section contexts. This
99 129 * // helps protect against arbitrary code execution when user input is passed directly into the template.
100 130 * // This currently defaults to false, but will default to true in v3.0.
101 131 * 'strict_callables' => true,
132 + *
133 + * // Enable pragmas across all templates, regardless of the presence of pragma tags in the individual
134 + * // templates.
135 + * 'pragmas' => [Mustache_Engine::PRAGMA_FILTERS],
102 136 * );
103 137 *
104 - * @throws Mustache_Exception_InvalidArgumentException If `escape` option is not callable.
138 + * @throws Mustache_Exception_InvalidArgumentException If `escape` option is not callable
105 139 *
106 140 * @param array $options (default: array())
107 141 */
108 142 public function __construct(array $options = array())
@@ -107,17 +141,28 @@
107 141 */
108 142 public function __construct(array $options = array())
109 143 {
110 144 if (isset($options['template_class_prefix'])) {
145 + if ((string) $options['template_class_prefix'] === '') {
146 + throw new Mustache_Exception_InvalidArgumentException('Mustache Constructor "template_class_prefix" must not be empty');
147 + }
148 +
111 149 $this->templateClassPrefix = $options['template_class_prefix'];
112 150 }
113 151
114 152 if (isset($options['cache'])) {
115 - $this->cache = $options['cache'];
153 + $cache = $options['cache'];
154 +
155 + if (is_string($cache)) {
156 + $mode = isset($options['cache_file_mode']) ? $options['cache_file_mode'] : null;
157 + $cache = new Mustache_Cache_FilesystemCache($cache, $mode);
158 + }
159 +
160 + $this->setCache($cache);
116 161 }
117 162
118 - if (isset($options['cache_file_mode'])) {
119 - $this->cacheFileMode = $options['cache_file_mode'];
163 + if (isset($options['cache_lambda_templates'])) {
164 + $this->cacheLambdaTemplates = (bool) $options['cache_lambda_templates'];
120 165 }
121 166
122 167 if (isset($options['loader'])) {
123 168 $this->setLoader($options['loader']);
@@ -143,9 +188,9 @@
143 188 $this->escape = $options['escape'];
144 189 }
145 190
146 191 if (isset($options['entity_flags'])) {
147 - $this->entityFlags = $options['entity_flags'];
192 + $this->entityFlags = $options['entity_flags'];
148 193 }
149 194
150 195 if (isset($options['charset'])) {
151 196 $this->charset = $options['charset'];
@@ -157,8 +202,21 @@
157 202
158 203 if (isset($options['strict_callables'])) {
159 204 $this->strictCallables = $options['strict_callables'];
160 205 }
206 +
207 + if (isset($options['delimiters'])) {
208 + $this->delimiters = $options['delimiters'];
209 + }
210 +
211 + if (isset($options['pragmas'])) {
212 + foreach ($options['pragmas'] as $pragma) {
213 + if (!isset(self::$knownPragmas[$pragma])) {
214 + throw new Mustache_Exception_InvalidArgumentException(sprintf('Unknown pragma: "%s".', $pragma));
215 + }
216 + $this->pragmas[$pragma] = true;
217 + }
218 + }
161 219 }
162 220
163 221 /**
164 222 * Shortcut 'render' invocation.
@@ -168,9 +226,9 @@
168 226 * @see Mustache_Engine::loadTemplate
169 227 * @see Mustache_Template::render
170 228 *
171 229 * @param string $template
172 - * @param mixed $context (default: array())
230 + * @param mixed $context (default: array())
173 231 *
174 232 * @return string Rendered template
175 233 */
176 234 public function render($template, $context = array())
@@ -180,9 +238,9 @@
180 238
181 239 /**
182 240 * Get the current Mustache escape callback.
183 241 *
184 - * @return mixed Callable or null
242 + * @return callable|null
185 243 */
186 244 public function getEscape()
187 245 {
188 246 return $this->escape;
@@ -194,9 +252,9 @@
194 252 * @return int
195 253 */
196 254 public function getEntityFlags()
197 255 {
198 - return $this->entityFlags;
256 + return $this->entityFlags;
199 257 }
200 258
201 259 /**
202 260 * Get the current Mustache character set.
@@ -208,8 +266,18 @@
208 266 return $this->charset;
209 267 }
210 268
211 269 /**
270 + * Get the current globally enabled pragmas.
271 + *
272 + * @return array
273 + */
274 + public function getPragmas()
275 + {
276 + return array_keys($this->pragmas);
277 + }
278 +
279 + /**
212 280 * Set the Mustache template Loader instance.
213 281 *
214 282 * @param Mustache_Loader $loader
215 283 */
@@ -228,9 +296,9 @@
228 296 */
229 297 public function getLoader()
230 298 {
231 299 if (!isset($this->loader)) {
232 - $this->loader = new Mustache_Loader_StringLoader;
300 + $this->loader = new Mustache_Loader_StringLoader();
233 301 }
234 302
235 303 return $this->loader;
236 304 }
@@ -255,9 +323,9 @@
255 323 */
256 324 public function getPartialsLoader()
257 325 {
258 326 if (!isset($this->partialsLoader)) {
259 - $this->partialsLoader = new Mustache_Loader_ArrayLoader;
327 + $this->partialsLoader = new Mustache_Loader_ArrayLoader();
260 328 }
261 329
262 330 return $this->partialsLoader;
263 331 }
@@ -271,9 +339,9 @@
271 339 */
272 340 public function setPartials(array $partials = array())
273 341 {
274 342 if (!isset($this->partialsLoader)) {
275 - $this->partialsLoader = new Mustache_Loader_ArrayLoader;
343 + $this->partialsLoader = new Mustache_Loader_ArrayLoader();
276 344 }
277 345
278 346 if (!$this->partialsLoader instanceof Mustache_Loader_MutableLoader) {
279 347 throw new Mustache_Exception_RuntimeException('Unable to set partials on an immutable Mustache Loader instance');
@@ -315,9 +383,9 @@
315 383 */
316 384 public function getHelpers()
317 385 {
318 386 if (!isset($this->helpers)) {
319 - $this->helpers = new Mustache_HelperCollection;
387 + $this->helpers = new Mustache_HelperCollection();
320 388 }
321 389
322 390 return $this->helpers;
323 391 }
@@ -355,9 +423,9 @@
355 423 * @see Mustache_Engine::setHelpers
356 424 *
357 425 * @param string $name
358 426 *
359 - * @return boolean True if the helper is present
427 + * @return bool True if the helper is present
360 428 */
361 429 public function hasHelper($name)
362 430 {
363 431 return $this->getHelpers()->has($name);
@@ -377,9 +445,9 @@
377 445
378 446 /**
379 447 * Set the Mustache Logger instance.
380 448 *
381 - * @throws Mustache_Exception_InvalidArgumentException If logger is not an instance of Mustache_Logger or Psr\Log\LoggerInterface.
449 + * @throws Mustache_Exception_InvalidArgumentException If logger is not an instance of Mustache_Logger or Psr\Log\LoggerInterface
382 450 *
383 451 * @param Mustache_Logger|Psr\Log\LoggerInterface $logger
384 452 */
385 453 public function setLogger($logger = null)
@@ -387,8 +455,12 @@
387 455 if ($logger !== null && !($logger instanceof Mustache_Logger || is_a($logger, 'Psr\\Log\\LoggerInterface'))) {
388 456 throw new Mustache_Exception_InvalidArgumentException('Expected an instance of Mustache_Logger or Psr\\Log\\LoggerInterface.');
389 457 }
390 458
459 + if ($this->getCache()->getLogger() === null) {
460 + $this->getCache()->setLogger($logger);
461 + }
462 +
391 463 $this->logger = $logger;
392 464 }
393 465
394 466 /**
@@ -420,9 +492,9 @@
420 492 */
421 493 public function getTokenizer()
422 494 {
423 495 if (!isset($this->tokenizer)) {
424 - $this->tokenizer = new Mustache_Tokenizer;
496 + $this->tokenizer = new Mustache_Tokenizer();
425 497 }
426 498
427 499 return $this->tokenizer;
428 500 }
@@ -446,9 +518,9 @@
446 518 */
447 519 public function getParser()
448 520 {
449 521 if (!isset($this->parser)) {
450 - $this->parser = new Mustache_Parser;
522 + $this->parser = new Mustache_Parser();
451 523 }
452 524
453 525 return $this->parser;
454 526 }
@@ -472,9 +544,9 @@
472 544 */
473 545 public function getCompiler()
474 546 {
475 547 if (!isset($this->compiler)) {
476 - $this->compiler = new Mustache_Compiler;
548 + $this->compiler = new Mustache_Compiler();
477 549 }
478 550
479 551 return $this->compiler;
480 552 }
@@ -479,25 +551,99 @@
479 551 return $this->compiler;
480 552 }
481 553
482 554 /**
555 + * Set the Mustache Cache instance.
556 + *
557 + * @param Mustache_Cache $cache
558 + */
559 + public function setCache(Mustache_Cache $cache)
560 + {
561 + if (isset($this->logger) && $cache->getLogger() === null) {
562 + $cache->setLogger($this->getLogger());
563 + }
564 +
565 + $this->cache = $cache;
566 + }
567 +
568 + /**
569 + * Get the current Mustache Cache instance.
570 + *
571 + * If no Cache instance has been explicitly specified, this method will instantiate and return a new one.
572 + *
573 + * @return Mustache_Cache
574 + */
575 + public function getCache()
576 + {
577 + if (!isset($this->cache)) {
578 + $this->setCache(new Mustache_Cache_NoopCache());
579 + }
580 +
581 + return $this->cache;
582 + }
583 +
584 + /**
585 + * Get the current Lambda Cache instance.
586 + *
587 + * If 'cache_lambda_templates' is enabled, this is the default cache instance. Otherwise, it is a NoopCache.
588 + *
589 + * @see Mustache_Engine::getCache
590 + *
591 + * @return Mustache_Cache
592 + */
593 + protected function getLambdaCache()
594 + {
595 + if ($this->cacheLambdaTemplates) {
596 + return $this->getCache();
597 + }
598 +
599 + if (!isset($this->lambdaCache)) {
600 + $this->lambdaCache = new Mustache_Cache_NoopCache();
601 + }
602 +
603 + return $this->lambdaCache;
604 + }
605 +
606 + /**
483 607 * Helper method to generate a Mustache template class.
484 608 *
485 - * @param string $source
609 + * This method must be updated any time options are added which make it so
610 + * the same template could be parsed and compiled multiple different ways.
486 611 *
612 + * @param string|Mustache_Source $source
613 + *
487 614 * @return string Mustache Template class name
488 615 */
489 616 public function getTemplateClassName($source)
490 617 {
491 - return $this->templateClassPrefix . md5(sprintf(
492 - 'version:%s,escape:%s,entity_flags:%i,charset:%s,strict_callables:%s,source:%s',
493 - self::VERSION,
494 - isset($this->escape) ? 'custom' : 'default',
495 - $this->entityFlags,
496 - $this->charset,
497 - $this->strictCallables ? 'true' : 'false',
498 - $source
499 - ));
618 + // For the most part, adding a new option here should do the trick.
619 + //
620 + // Pick a value here which is unique for each possible way the template
621 + // could be compiled... but not necessarily unique per option value. See
622 + // escape below, which only needs to differentiate between 'custom' and
623 + // 'default' escapes.
624 + //
625 + // Keep this list in alphabetical order :)
626 + $chunks = array(
627 + 'charset' => $this->charset,
628 + 'delimiters' => $this->delimiters ? $this->delimiters : '{{ }}',
629 + 'entityFlags' => $this->entityFlags,
630 + 'escape' => isset($this->escape) ? 'custom' : 'default',
631 + 'key' => ($source instanceof Mustache_Source) ? $source->getKey() : 'source',
632 + 'pragmas' => $this->getPragmas(),
633 + 'strictCallables' => $this->strictCallables,
634 + 'version' => self::VERSION,
635 + );
636 +
637 + $key = json_encode($chunks);
638 +
639 + // Template Source instances have already provided their own source key. For strings, just include the whole
640 + // source string in the md5 hash.
641 + if (!$source instanceof Mustache_Source) {
642 + $key .= "\n" . $source;
643 + }
644 +
645 + return $this->templateClassPrefix . md5($key);
500 646 }
501 647
502 648 /**
503 649 * Load a Mustache Template by name.
@@ -559,48 +705,39 @@
559 705 if ($delims !== null) {
560 706 $source = $delims . "\n" . $source;
561 707 }
562 708
563 - return $this->loadSource($source);
709 + return $this->loadSource($source, $this->getLambdaCache());
564 710 }
565 711
566 712 /**
567 713 * Instantiate and return a Mustache Template instance by source.
568 714 *
715 + * Optionally provide a Mustache_Cache instance. This is used internally by Mustache_Engine::loadLambda to respect
716 + * the 'cache_lambda_templates' configuration option.
717 + *
569 718 * @see Mustache_Engine::loadTemplate
570 719 * @see Mustache_Engine::loadPartial
571 720 * @see Mustache_Engine::loadLambda
572 721 *
573 - * @param string $source
722 + * @param string|Mustache_Source $source
723 + * @param Mustache_Cache $cache (default: null)
574 724 *
575 725 * @return Mustache_Template
576 726 */
577 - private function loadSource($source)
727 + private function loadSource($source, ?Mustache_Cache $cache = null)
578 728 {
579 729 $className = $this->getTemplateClassName($source);
580 730
581 731 if (!isset($this->templates[$className])) {
732 + if ($cache === null) {
733 + $cache = $this->getCache();
734 + }
735 +
582 736 if (!class_exists($className, false)) {
583 - if ($fileName = $this->getCacheFilename($source)) {
584 - if (!is_file($fileName)) {
585 - $this->log(
586 - Mustache_Logger::DEBUG,
587 - 'Writing "{className}" class to template cache: "{fileName}"',
588 - array('className' => $className, 'fileName' => $fileName)
589 - );
590 -
591 - $this->writeCacheFile($fileName, $this->compile($source));
592 - }
593 -
594 - require_once $fileName;
595 - } else {
596 - $this->log(
597 - Mustache_Logger::WARNING,
598 - 'Template cache disabled, evaluating "{className}" class at runtime',
599 - array('className' => $className)
600 - );
601 -
602 - eval('?>'.$this->compile($source));
737 + if (!$cache->load($className)) {
738 + $compiled = $this->compile($source);
739 + $cache->cache($className, $compiled);
603 740 }
604 741 }
605 742
606 743 $this->log(
@@ -625,9 +762,9 @@
625 762 * @return array Tokens
626 763 */
627 764 private function tokenize($source)
628 765 {
629 - return $this->getTokenizer()->scan($source);
766 + return $this->getTokenizer()->scan($source, $this->delimiters);
630 767 }
631 768
632 769 /**
633 770 * Helper method to parse a Mustache template.
@@ -639,9 +776,12 @@
639 776 * @return array Token tree
640 777 */
641 778 private function parse($source)
642 779 {
643 - return $this->getParser()->parse($this->tokenize($source));
780 + $parser = $this->getParser();
781 + $parser->setPragmas($this->getPragmas());
782 +
783 + return $parser->parse($this->tokenize($source));
644 784 }
645 785
646 786 /**
647 787 * Helper method to compile a Mustache template.
@@ -647,15 +787,14 @@
647 787 * Helper method to compile a Mustache template.
648 788 *
649 789 * @see Mustache_Compiler::compile
650 790 *
651 - * @param string $source
791 + * @param string|Mustache_Source $source
652 792 *
653 793 * @return string generated Mustache template class code
654 794 */
655 795 private function compile($source)
656 796 {
657 - $tree = $this->parse($source);
658 797 $name = $this->getTemplateClassName($source);
659 798
660 799 $this->log(
661 800 Mustache_Logger::INFO,
@@ -662,83 +801,25 @@
662 801 'Compiling template to "{className}" class',
663 802 array('className' => $name)
664 803 );
665 804
666 - return $this->getCompiler()->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables, $this->entityFlags);
667 - }
668 -
669 - /**
670 - * Helper method to generate a Mustache Template class cache filename.
671 - *
672 - * @param string $source
673 - *
674 - * @return string Mustache Template class cache filename
675 - */
676 - private function getCacheFilename($source)
677 - {
678 - if ($this->cache) {
679 - return sprintf('%s/%s.php', $this->cache, $this->getTemplateClassName($source));
805 + if ($source instanceof Mustache_Source) {
806 + $source = $source->getSource();
680 807 }
681 - }
808 + $tree = $this->parse($source);
682 809
683 - /**
684 - * Helper method to dump a generated Mustache Template subclass to the file cache.
685 - *
686 - * @throws Mustache_Exception_RuntimeException if unable to create the cache directory or write to $fileName.
687 - *
688 - * @param string $fileName
689 - * @param string $source
690 - *
691 - * @codeCoverageIgnore
692 - */
693 - private function writeCacheFile($fileName, $source)
694 - {
695 - $dirName = dirname($fileName);
696 - if (!is_dir($dirName)) {
697 - $this->log(
698 - Mustache_Logger::INFO,
699 - 'Creating Mustache template cache directory: "{dirName}"',
700 - array('dirName' => $dirName)
701 - );
810 + $compiler = $this->getCompiler();
811 + $compiler->setPragmas($this->getPragmas());
702 812
703 - @mkdir($dirName, 0777, true);
704 - if (!is_dir($dirName)) {
705 - throw new Mustache_Exception_RuntimeException(sprintf('Failed to create cache directory "%s".', $dirName));
706 - }
707 -
708 - }
709 -
710 - $this->log(
711 - Mustache_Logger::DEBUG,
712 - 'Caching compiled template to "{fileName}"',
713 - array('fileName' => $fileName)
714 - );
715 -
716 - $tempFile = tempnam($dirName, basename($fileName));
717 - if (false !== @file_put_contents($tempFile, $source)) {
718 - if (@rename($tempFile, $fileName)) {
719 - $mode = isset($this->cacheFileMode) ? $this->cacheFileMode : (0666 & ~umask());
720 - @chmod($fileName, $mode);
721 -
722 - return;
723 - }
724 -
725 - $this->log(
726 - Mustache_Logger::ERROR,
727 - 'Unable to rename Mustache temp cache file: "{tempName}" -> "{fileName}"',
728 - array('tempName' => $tempFile, 'fileName' => $fileName)
729 - );
730 - }
731 -
732 - throw new Mustache_Exception_RuntimeException(sprintf('Failed to write cache file "%s".', $fileName));
813 + return $compiler->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables, $this->entityFlags);
733 814 }
734 815
735 816 /**
736 817 * Add a log record if logging is enabled.
737 818 *
738 - * @param integer $level The logging level
739 - * @param string $message The log message
740 - * @param array $context The log context
819 + * @param int $level The logging level
820 + * @param string $message The log message
821 + * @param array $context The log context
741 822 */
742 823 private function log($level, $message, array $context = array())
743 824 {
744 825 if (isset($this->logger)) {