/library/Zend/View/TemplatePathStack.php

https://github.com/bruisedlee/zf2 · PHP · 291 lines · 146 code · 24 blank · 121 comment · 19 complexity · d01c1c32508c723ecaa33a7f478f9941 MD5 · raw file

  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_View
  17. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. */
  20. /**
  21. * @namespace
  22. */
  23. namespace Zend\View;
  24. use SplFileInfo,
  25. Zend\Stdlib\SplStack;
  26. /**
  27. * Resolves view scripts based on a stack of paths
  28. *
  29. * @category Zend
  30. * @package Zend_View
  31. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  32. * @license http://framework.zend.com/license/new-bsd New BSD License
  33. */
  34. class TemplatePathStack implements TemplateResolver
  35. {
  36. /**
  37. * @var SplStack
  38. */
  39. protected $paths;
  40. /**
  41. * Flag indicating whether or not LFI protection for rendering view scripts is enabled
  42. * @var bool
  43. */
  44. protected $lfiProtectionOn = true;
  45. /**@+
  46. * Flags used to determine if a stream wrapper should be used for enabling short tags
  47. * @var bool
  48. */
  49. protected $useViewStream = false;
  50. protected $useStreamWrapper = false;
  51. /**@-*/
  52. /**
  53. * Constructor
  54. *
  55. * @param null|array|Traversable $options
  56. * @return void
  57. */
  58. public function __construct($options = null)
  59. {
  60. $this->useViewStream = (bool) ini_get('short_open_tag');
  61. if ($this->useViewStream) {
  62. if (!in_array('zend.view', stream_get_wrappers())) {
  63. stream_wrapper_register('zend.view', 'Zend\View\Stream');
  64. }
  65. }
  66. $this->paths = new SplStack;
  67. if (null !== $options) {
  68. $this->setOptions($options);
  69. }
  70. }
  71. /**
  72. * Configure object
  73. *
  74. * @param array|Traversable $options
  75. * @return void
  76. */
  77. public function setOptions($options)
  78. {
  79. if (!is_array($options) && !$options instanceof \Traversable) {
  80. throw new Exception(sprintf(
  81. 'Expected array or Traversable object; received "%s"',
  82. (is_object($options) ? get_class($options) : gettype($options))
  83. ));
  84. }
  85. foreach ($options as $key => $value) {
  86. switch (strtolower($key)) {
  87. case 'lfi_protection':
  88. $this->setLfiProtection($value);
  89. break;
  90. case 'script_paths':
  91. $this->addPaths($value);
  92. break;
  93. case 'use_stream_wrapper':
  94. $this->setUseStreamWrapper($value);
  95. break;
  96. default:
  97. break;
  98. }
  99. }
  100. }
  101. /**
  102. * Add many paths to the stack at once
  103. *
  104. * @param array $paths
  105. * @return TemplatePathStack
  106. */
  107. public function addPaths(array $paths)
  108. {
  109. foreach ($paths as $path) {
  110. $this->addPath($path);
  111. }
  112. return $this;
  113. }
  114. /**
  115. * Rest the path stack to the paths provided
  116. *
  117. * @param SplStack|array $paths
  118. * @return TemplatePathStack
  119. */
  120. public function setPaths($paths)
  121. {
  122. if ($paths instanceof SplStack) {
  123. $this->paths = $paths;
  124. } elseif (is_array($paths)) {
  125. $this->clearPaths();
  126. $this->addPaths($paths);
  127. } else {
  128. throw new InvalidArgumentException(
  129. "Invalid argument provided for \$paths, expecting either an array or SplStack object"
  130. );
  131. }
  132. return $this;
  133. }
  134. /**
  135. * Normalize a path for insertion in the stack
  136. *
  137. * @param string $path
  138. * @return string
  139. */
  140. public static function normalizePath($path)
  141. {
  142. $path = rtrim($path, '/');
  143. $path = rtrim($path, '\\');
  144. $path .= DIRECTORY_SEPARATOR;
  145. return $path;
  146. }
  147. /**
  148. * Add a single path to the stack
  149. *
  150. * @param string $path
  151. * @return TemplatePathStack
  152. */
  153. public function addPath($path)
  154. {
  155. if (!is_string($path)) {
  156. throw new Exception(sprintf(
  157. 'Invalid path provided; must be a string, received %s',
  158. gettype($path)
  159. ));
  160. }
  161. $this->paths[] = static::normalizePath($path);
  162. return $this;
  163. }
  164. /**
  165. * Clear all paths
  166. *
  167. * @return void
  168. */
  169. public function clearPaths()
  170. {
  171. $this->paths = new SplStack;
  172. }
  173. /**
  174. * Returns stack of paths
  175. *
  176. * @return SplStack
  177. */
  178. public function getPaths()
  179. {
  180. return $this->paths;
  181. }
  182. /**
  183. * Set LFI protection flag
  184. *
  185. * @param bool $flag
  186. * @return \Zend\View\TemplatePathStack
  187. */
  188. public function setLfiProtection($flag)
  189. {
  190. $this->lfiProtectionOn = (bool) $flag;
  191. return $this;
  192. }
  193. /**
  194. * Return status of LFI protection flag
  195. *
  196. * @return bool
  197. */
  198. public function isLfiProtectionOn()
  199. {
  200. return $this->lfiProtectionOn;
  201. }
  202. /**
  203. * Set flag indicating if stream wrapper should be used if short_open_tag is off
  204. *
  205. * @param bool $flag
  206. * @return \Zend\View\View
  207. */
  208. public function setUseStreamWrapper($flag)
  209. {
  210. $this->useStreamWrapper = (bool) $flag;
  211. return $this;
  212. }
  213. /**
  214. * Should the stream wrapper be used if short_open_tag is off?
  215. *
  216. * Returns true if the use_stream_wrapper flag is set, and if short_open_tag
  217. * is disabled.
  218. *
  219. * @return bool
  220. */
  221. public function useStreamWrapper()
  222. {
  223. return ($this->useViewStream && $this->useStreamWrapper);
  224. }
  225. /**
  226. * Retrieve the filesystem path to a view script
  227. *
  228. * @param string $name
  229. * @return string
  230. */
  231. public function getScriptPath($name)
  232. {
  233. if ($this->isLfiProtectionOn() && preg_match('#\.\.[\\\/]#', $name)) {
  234. $e = new Exception('Requested scripts may not include parent directory traversal ("../", "..\\" notation)');
  235. throw $e;
  236. }
  237. if (!count($this->paths)) {
  238. $e = new Exception('No view script directory set; unable to determine location for view script');
  239. throw $e;
  240. }
  241. $paths = PATH_SEPARATOR;
  242. foreach ($this->paths as $path) {
  243. $file = new SplFileInfo($path . $name);
  244. if ($file->isReadable()) {
  245. // Found! Return it.
  246. if (($filePath = $file->getRealPath()) === false && substr($path, 0, 7) === 'phar://') {
  247. // Do not try to expand phar paths (realpath + phars == fail)
  248. $filePath = $path . $name;
  249. if (!file_exists($filePath)) {
  250. break;
  251. }
  252. }
  253. if ($this->useStreamWrapper()) {
  254. // If using a stream wrapper, prepend the spec to the path
  255. $filePath = 'zend.view://' . $filePath;
  256. }
  257. return $filePath;
  258. }
  259. $paths .= $path . PATH_SEPARATOR;
  260. }
  261. $e = new Exception(sprintf(
  262. 'Script "%s" not found in path (%s)',
  263. $name, trim($paths, PATH_SEPARATOR)
  264. ));
  265. throw $e;
  266. }
  267. }