Abstract.php 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136
  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-2009 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id$
  20. */
  21. /** Zend_Loader */
  22. require_once 'Zend/Loader.php';
  23. /** Zend_Loader_PluginLoader */
  24. require_once 'Zend/Loader/PluginLoader.php';
  25. /** Zend_View_Interface */
  26. require_once 'Zend/View/Interface.php';
  27. /**
  28. * Abstract class for Zend_View to help enforce private constructs.
  29. *
  30. * @category Zend
  31. * @package Zend_View
  32. * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  33. * @license http://framework.zend.com/license/new-bsd New BSD License
  34. */
  35. abstract class Zend_View_Abstract implements Zend_View_Interface
  36. {
  37. /**
  38. * Path stack for script, helper, and filter directories.
  39. *
  40. * @var array
  41. */
  42. private $_path = array(
  43. 'script' => array(),
  44. 'helper' => array(),
  45. 'filter' => array(),
  46. );
  47. /**
  48. * Script file name to execute
  49. *
  50. * @var string
  51. */
  52. private $_file = null;
  53. /**
  54. * Instances of helper objects.
  55. *
  56. * @var array
  57. */
  58. private $_helper = array();
  59. /**
  60. * Map of helper => class pairs to help in determining helper class from
  61. * name
  62. * @var array
  63. */
  64. private $_helperLoaded = array();
  65. /**
  66. * Map of helper => classfile pairs to aid in determining helper classfile
  67. * @var array
  68. */
  69. private $_helperLoadedDir = array();
  70. /**
  71. * Stack of Zend_View_Filter names to apply as filters.
  72. * @var array
  73. */
  74. private $_filter = array();
  75. /**
  76. * Stack of Zend_View_Filter objects that have been loaded
  77. * @var array
  78. */
  79. private $_filterClass = array();
  80. /**
  81. * Map of filter => class pairs to help in determining filter class from
  82. * name
  83. * @var array
  84. */
  85. private $_filterLoaded = array();
  86. /**
  87. * Map of filter => classfile pairs to aid in determining filter classfile
  88. * @var array
  89. */
  90. private $_filterLoadedDir = array();
  91. /**
  92. * Callback for escaping.
  93. *
  94. * @var string
  95. */
  96. private $_escape = 'htmlspecialchars';
  97. /**
  98. * Encoding to use in escaping mechanisms; defaults to latin1 (ISO-8859-1)
  99. * @var string
  100. */
  101. private $_encoding = 'ISO-8859-1';
  102. /**
  103. * Flag indicating whether or not LFI protection for rendering view scripts is enabled
  104. * @var bool
  105. */
  106. private $_lfiProtectionOn = true;
  107. /**
  108. * Plugin loaders
  109. * @var array
  110. */
  111. private $_loaders = array();
  112. /**
  113. * Plugin types
  114. * @var array
  115. */
  116. private $_loaderTypes = array('filter', 'helper');
  117. /**
  118. * Strict variables flag; when on, undefined variables accessed in the view
  119. * scripts will trigger notices
  120. * @var boolean
  121. */
  122. private $_strictVars = false;
  123. private $_log;
  124. /**
  125. * Constructor.
  126. *
  127. * @param array $config Configuration key-value pairs.
  128. */
  129. public function __construct($config = array())
  130. {
  131. // set inital paths and properties
  132. $this->setScriptPath(null);
  133. // $this->setHelperPath(null);
  134. $this->setFilterPath(null);
  135. // user-defined escaping callback
  136. if (array_key_exists('escape', $config)) {
  137. $this->setEscape($config['escape']);
  138. }
  139. // encoding
  140. if (array_key_exists('encoding', $config)) {
  141. $this->setEncoding($config['encoding']);
  142. }
  143. // base path
  144. if (array_key_exists('basePath', $config)) {
  145. $prefix = 'Zend_View';
  146. if (array_key_exists('basePathPrefix', $config)) {
  147. $prefix = $config['basePathPrefix'];
  148. }
  149. $this->setBasePath($config['basePath'], $prefix);
  150. }
  151. // user-defined view script path
  152. if (array_key_exists('scriptPath', $config)) {
  153. $this->addScriptPath($config['scriptPath']);
  154. }
  155. // user-defined helper path
  156. if (array_key_exists('helperPath', $config)) {
  157. if (is_array($config['helperPath'])) {
  158. foreach ($config['helperPath'] as $prefix => $path) {
  159. $this->addHelperPath($path, $prefix);
  160. }
  161. } else {
  162. $prefix = 'Zend_View_Helper';
  163. if (array_key_exists('helperPathPrefix', $config)) {
  164. $prefix = $config['helperPathPrefix'];
  165. }
  166. $this->addHelperPath($config['helperPath'], $prefix);
  167. }
  168. }
  169. // user-defined filter path
  170. if (array_key_exists('filterPath', $config)) {
  171. if (is_array($config['filterPath'])) {
  172. foreach ($config['filterPath'] as $prefix => $path) {
  173. $this->addFilterPath($path, $prefix);
  174. }
  175. } else {
  176. $prefix = 'Zend_View_Filter';
  177. if (array_key_exists('filterPathPrefix', $config)) {
  178. $prefix = $config['filterPathPrefix'];
  179. }
  180. $this->addFilterPath($config['filterPath'], $prefix);
  181. }
  182. }
  183. // user-defined filters
  184. if (array_key_exists('filter', $config)) {
  185. $this->addFilter($config['filter']);
  186. }
  187. // strict vars
  188. if (array_key_exists('strictVars', $config)) {
  189. $this->strictVars($config['strictVars']);
  190. }
  191. // LFI protection flag
  192. if (array_key_exists('lfiProtectionOn', $config)) {
  193. $this->setLfiProtection($config['lfiProtectionOn']);
  194. }
  195. $this->init();
  196. }
  197. /**
  198. * Return the template engine object
  199. *
  200. * Returns the object instance, as it is its own template engine
  201. *
  202. * @return Zend_View_Abstract
  203. */
  204. public function getEngine()
  205. {
  206. return $this;
  207. }
  208. /**
  209. * Allow custom object initialization when extending Zend_View_Abstract or
  210. * Zend_View
  211. *
  212. * Triggered by {@link __construct() the constructor} as its final action.
  213. *
  214. * @return void
  215. */
  216. public function init()
  217. {
  218. }
  219. /**
  220. * Prevent E_NOTICE for nonexistent values
  221. *
  222. * If {@link strictVars()} is on, raises a notice.
  223. *
  224. * @param string $key
  225. * @return null
  226. */
  227. public function __get($key)
  228. {
  229. if ($this->_strictVars) {
  230. trigger_error('Key "' . $key . '" does not exist', E_USER_NOTICE);
  231. }
  232. return null;
  233. }
  234. /**
  235. * Allows testing with empty() and isset() to work inside
  236. * templates.
  237. *
  238. * @param string $key
  239. * @return boolean
  240. */
  241. public function __isset($key)
  242. {
  243. if ('_' != substr($key, 0, 1)) {
  244. return isset($this->$key);
  245. }
  246. return false;
  247. }
  248. /**
  249. * Directly assigns a variable to the view script.
  250. *
  251. * Checks first to ensure that the caller is not attempting to set a
  252. * protected or private member (by checking for a prefixed underscore); if
  253. * not, the public member is set; otherwise, an exception is raised.
  254. *
  255. * @param string $key The variable name.
  256. * @param mixed $val The variable value.
  257. * @return void
  258. * @throws Zend_View_Exception if an attempt to set a private or protected
  259. * member is detected
  260. */
  261. public function __set($key, $val)
  262. {
  263. if ('_' != substr($key, 0, 1)) {
  264. $this->$key = $val;
  265. return;
  266. }
  267. require_once 'Zend/View/Exception.php';
  268. throw new Zend_View_Exception('Setting private or protected class members is not allowed', $this);
  269. }
  270. /**
  271. * Allows unset() on object properties to work
  272. *
  273. * @param string $key
  274. * @return void
  275. */
  276. public function __unset($key)
  277. {
  278. if ('_' != substr($key, 0, 1) && isset($this->$key)) {
  279. unset($this->$key);
  280. }
  281. }
  282. /**
  283. * Accesses a helper object from within a script.
  284. *
  285. * If the helper class has a 'view' property, sets it with the current view
  286. * object.
  287. *
  288. * @param string $name The helper name.
  289. * @param array $args The parameters for the helper.
  290. * @return string The result of the helper output.
  291. */
  292. public function __call($name, $args)
  293. {
  294. // is the helper already loaded?
  295. $helper = $this->getHelper($name);
  296. // call the helper method
  297. return call_user_func_array(
  298. array($helper, $name),
  299. $args
  300. );
  301. }
  302. /**
  303. * Given a base path, sets the script, helper, and filter paths relative to it
  304. *
  305. * Assumes a directory structure of:
  306. * <code>
  307. * basePath/
  308. * scripts/
  309. * helpers/
  310. * filters/
  311. * </code>
  312. *
  313. * @param string $path
  314. * @param string $prefix Prefix to use for helper and filter paths
  315. * @return Zend_View_Abstract
  316. */
  317. public function setBasePath($path, $classPrefix = 'Zend_View')
  318. {
  319. $path = rtrim($path, '/');
  320. $path = rtrim($path, '\\');
  321. $path .= DIRECTORY_SEPARATOR;
  322. $classPrefix = rtrim($classPrefix, '_') . '_';
  323. $this->setScriptPath($path . 'scripts');
  324. $this->setHelperPath($path . 'helpers', $classPrefix . 'Helper');
  325. $this->setFilterPath($path . 'filters', $classPrefix . 'Filter');
  326. return $this;
  327. }
  328. /**
  329. * Given a base path, add script, helper, and filter paths relative to it
  330. *
  331. * Assumes a directory structure of:
  332. * <code>
  333. * basePath/
  334. * scripts/
  335. * helpers/
  336. * filters/
  337. * </code>
  338. *
  339. * @param string $path
  340. * @param string $prefix Prefix to use for helper and filter paths
  341. * @return Zend_View_Abstract
  342. */
  343. public function addBasePath($path, $classPrefix = 'Zend_View')
  344. {
  345. $path = rtrim($path, '/');
  346. $path = rtrim($path, '\\');
  347. $path .= DIRECTORY_SEPARATOR;
  348. $classPrefix = rtrim($classPrefix, '_') . '_';
  349. $this->addScriptPath($path . 'scripts');
  350. $this->addHelperPath($path . 'helpers', $classPrefix . 'Helper');
  351. $this->addFilterPath($path . 'filters', $classPrefix . 'Filter');
  352. return $this;
  353. }
  354. /**
  355. * Adds to the stack of view script paths in LIFO order.
  356. *
  357. * @param string|array The directory (-ies) to add.
  358. * @return Zend_View_Abstract
  359. */
  360. public function addScriptPath($path)
  361. {
  362. $this->_addPath('script', $path);
  363. return $this;
  364. }
  365. /**
  366. * Resets the stack of view script paths.
  367. *
  368. * To clear all paths, use Zend_View::setScriptPath(null).
  369. *
  370. * @param string|array The directory (-ies) to set as the path.
  371. * @return Zend_View_Abstract
  372. */
  373. public function setScriptPath($path)
  374. {
  375. $this->_path['script'] = array();
  376. $this->_addPath('script', $path);
  377. return $this;
  378. }
  379. /**
  380. * Return full path to a view script specified by $name
  381. *
  382. * @param string $name
  383. * @return false|string False if script not found
  384. * @throws Zend_View_Exception if no script directory set
  385. */
  386. public function getScriptPath($name)
  387. {
  388. try {
  389. $path = $this->_script($name);
  390. return $path;
  391. } catch (Zend_View_Exception $e) {
  392. if (strstr($e->getMessage(), 'no view script directory set')) {
  393. throw $e;
  394. }
  395. return false;
  396. }
  397. }
  398. /**
  399. * Returns an array of all currently set script paths
  400. *
  401. * @return array
  402. */
  403. public function getScriptPaths()
  404. {
  405. return $this->_getPaths('script');
  406. }
  407. /**
  408. * Set plugin loader for a particular plugin type
  409. *
  410. * @param Zend_Loader_PluginLoader $loader
  411. * @param string $type
  412. * @return Zend_View_Abstract
  413. */
  414. public function setPluginLoader(Zend_Loader_PluginLoader $loader, $type)
  415. {
  416. $type = strtolower($type);
  417. if (!in_array($type, $this->_loaderTypes)) {
  418. require_once 'Zend/View/Exception.php';
  419. throw new Zend_View_Exception(sprintf('Invalid plugin loader type "%s"', $type));
  420. }
  421. $this->_loaders[$type] = $loader;
  422. return $this;
  423. }
  424. /**
  425. * Retrieve plugin loader for a specific plugin type
  426. *
  427. * @param string $type
  428. * @return Zend_Loader_PluginLoader
  429. */
  430. public function getPluginLoader($type)
  431. {
  432. $type = strtolower($type);
  433. if (!in_array($type, $this->_loaderTypes)) {
  434. require_once 'Zend/View/Exception.php';
  435. throw new Zend_View_Exception(sprintf('Invalid plugin loader type "%s"; cannot retrieve', $type));
  436. }
  437. if (!array_key_exists($type, $this->_loaders)) {
  438. $prefix = 'Zend_View_';
  439. $pathPrefix = 'Zend/View/';
  440. $pType = ucfirst($type);
  441. switch ($type) {
  442. case 'filter':
  443. case 'helper':
  444. default:
  445. $prefix .= $pType;
  446. $pathPrefix .= $pType;
  447. $loader = new Zend_Loader_PluginLoader(array(
  448. $prefix => $pathPrefix
  449. ));
  450. $this->_loaders[$type] = $loader;
  451. break;
  452. }
  453. }
  454. return $this->_loaders[$type];
  455. }
  456. /**
  457. * Adds to the stack of helper paths in LIFO order.
  458. *
  459. * @param string|array The directory (-ies) to add.
  460. * @param string $classPrefix Class prefix to use with classes in this
  461. * directory; defaults to Zend_View_Helper
  462. * @return Zend_View_Abstract
  463. */
  464. public function addHelperPath($path, $classPrefix = 'Zend_View_Helper_')
  465. {
  466. return $this->_addPluginPath('helper', $classPrefix, (array) $path);
  467. }
  468. /**
  469. * Resets the stack of helper paths.
  470. *
  471. * To clear all paths, use Zend_View::setHelperPath(null).
  472. *
  473. * @param string|array $path The directory (-ies) to set as the path.
  474. * @param string $classPrefix The class prefix to apply to all elements in
  475. * $path; defaults to Zend_View_Helper
  476. * @return Zend_View_Abstract
  477. */
  478. public function setHelperPath($path, $classPrefix = 'Zend_View_Helper_')
  479. {
  480. unset($this->_loaders['helper']);
  481. return $this->addHelperPath($path, $classPrefix);
  482. }
  483. /**
  484. * Get full path to a helper class file specified by $name
  485. *
  486. * @param string $name
  487. * @return string|false False on failure, path on success
  488. */
  489. public function getHelperPath($name)
  490. {
  491. return $this->_getPluginPath('helper', $name);
  492. }
  493. /**
  494. * Returns an array of all currently set helper paths
  495. *
  496. * @return array
  497. */
  498. public function getHelperPaths()
  499. {
  500. return $this->getPluginLoader('helper')->getPaths();
  501. }
  502. /**
  503. * Get a helper by name
  504. *
  505. * @param string $name
  506. * @return object
  507. */
  508. public function getHelper($name)
  509. {
  510. return $this->_getPlugin('helper', $name);
  511. }
  512. /**
  513. * Get array of all active helpers
  514. *
  515. * Only returns those that have already been instantiated.
  516. *
  517. * @return array
  518. */
  519. public function getHelpers()
  520. {
  521. return $this->_helper;
  522. }
  523. /**
  524. * Adds to the stack of filter paths in LIFO order.
  525. *
  526. * @param string|array The directory (-ies) to add.
  527. * @param string $classPrefix Class prefix to use with classes in this
  528. * directory; defaults to Zend_View_Filter
  529. * @return Zend_View_Abstract
  530. */
  531. public function addFilterPath($path, $classPrefix = 'Zend_View_Filter_')
  532. {
  533. return $this->_addPluginPath('filter', $classPrefix, (array) $path);
  534. }
  535. /**
  536. * Resets the stack of filter paths.
  537. *
  538. * To clear all paths, use Zend_View::setFilterPath(null).
  539. *
  540. * @param string|array The directory (-ies) to set as the path.
  541. * @param string $classPrefix The class prefix to apply to all elements in
  542. * $path; defaults to Zend_View_Filter
  543. * @return Zend_View_Abstract
  544. */
  545. public function setFilterPath($path, $classPrefix = 'Zend_View_Filter_')
  546. {
  547. unset($this->_loaders['filter']);
  548. return $this->addFilterPath($path, $classPrefix);
  549. }
  550. /**
  551. * Get full path to a filter class file specified by $name
  552. *
  553. * @param string $name
  554. * @return string|false False on failure, path on success
  555. */
  556. public function getFilterPath($name)
  557. {
  558. return $this->_getPluginPath('filter', $name);
  559. }
  560. /**
  561. * Get a filter object by name
  562. *
  563. * @param string $name
  564. * @return object
  565. */
  566. public function getFilter($name)
  567. {
  568. return $this->_getPlugin('filter', $name);
  569. }
  570. /**
  571. * Return array of all currently active filters
  572. *
  573. * Only returns those that have already been instantiated.
  574. *
  575. * @return array
  576. */
  577. public function getFilters()
  578. {
  579. return $this->_filter;
  580. }
  581. /**
  582. * Returns an array of all currently set filter paths
  583. *
  584. * @return array
  585. */
  586. public function getFilterPaths()
  587. {
  588. return $this->getPluginLoader('filter')->getPaths();
  589. }
  590. /**
  591. * Return associative array of path types => paths
  592. *
  593. * @return array
  594. */
  595. public function getAllPaths()
  596. {
  597. $paths = $this->_path;
  598. $paths['helper'] = $this->getHelperPaths();
  599. $paths['filter'] = $this->getFilterPaths();
  600. return $paths;
  601. }
  602. /**
  603. * Add one or more filters to the stack in FIFO order.
  604. *
  605. * @param string|array One or more filters to add.
  606. * @return Zend_View_Abstract
  607. */
  608. public function addFilter($name)
  609. {
  610. foreach ((array) $name as $val) {
  611. $this->_filter[] = $val;
  612. }
  613. return $this;
  614. }
  615. /**
  616. * Resets the filter stack.
  617. *
  618. * To clear all filters, use Zend_View::setFilter(null).
  619. *
  620. * @param string|array One or more filters to set.
  621. * @return Zend_View_Abstract
  622. */
  623. public function setFilter($name)
  624. {
  625. $this->_filter = array();
  626. $this->addFilter($name);
  627. return $this;
  628. }
  629. /**
  630. * Sets the _escape() callback.
  631. *
  632. * @param mixed $spec The callback for _escape() to use.
  633. * @return Zend_View_Abstract
  634. */
  635. public function setEscape($spec)
  636. {
  637. $this->_escape = $spec;
  638. return $this;
  639. }
  640. /**
  641. * Set LFI protection flag
  642. *
  643. * @param bool $flag
  644. * @return Zend_View_Abstract
  645. */
  646. public function setLfiProtection($flag)
  647. {
  648. $this->_lfiProtectionOn = (bool) $flag;
  649. return $this;
  650. }
  651. /**
  652. * Return status of LFI protection flag
  653. *
  654. * @return bool
  655. */
  656. public function isLfiProtectionOn()
  657. {
  658. return $this->_lfiProtectionOn;
  659. }
  660. /**
  661. * Assigns variables to the view script via differing strategies.
  662. *
  663. * Zend_View::assign('name', $value) assigns a variable called 'name'
  664. * with the corresponding $value.
  665. *
  666. * Zend_View::assign($array) assigns the array keys as variable
  667. * names (with the corresponding array values).
  668. *
  669. * @see __set()
  670. * @param string|array The assignment strategy to use.
  671. * @param mixed (Optional) If assigning a named variable, use this
  672. * as the value.
  673. * @return Zend_View_Abstract Fluent interface
  674. * @throws Zend_View_Exception if $spec is neither a string nor an array,
  675. * or if an attempt to set a private or protected member is detected
  676. */
  677. public function assign($spec, $value = null)
  678. {
  679. // which strategy to use?
  680. if (is_string($spec)) {
  681. // assign by name and value
  682. if ('_' == substr($spec, 0, 1)) {
  683. require_once 'Zend/View/Exception.php';
  684. throw new Zend_View_Exception('Setting private or protected class members is not allowed', $this);
  685. }
  686. $this->$spec = $value;
  687. } elseif (is_array($spec)) {
  688. // assign from associative array
  689. $error = false;
  690. foreach ($spec as $key => $val) {
  691. if ('_' == substr($key, 0, 1)) {
  692. $error = true;
  693. break;
  694. }
  695. $this->$key = $val;
  696. }
  697. if ($error) {
  698. require_once 'Zend/View/Exception.php';
  699. throw new Zend_View_Exception('Setting private or protected class members is not allowed', $this);
  700. }
  701. } else {
  702. require_once 'Zend/View/Exception.php';
  703. throw new Zend_View_Exception('assign() expects a string or array, received ' . gettype($spec), $this);
  704. }
  705. return $this;
  706. }
  707. /**
  708. * Return list of all assigned variables
  709. *
  710. * Returns all public properties of the object. Reflection is not used
  711. * here as testing reflection properties for visibility is buggy.
  712. *
  713. * @return array
  714. */
  715. public function getVars()
  716. {
  717. $vars = get_object_vars($this);
  718. foreach ($vars as $key => $value) {
  719. if ('_' == substr($key, 0, 1)) {
  720. unset($vars[$key]);
  721. }
  722. }
  723. return $vars;
  724. }
  725. /**
  726. * Clear all assigned variables
  727. *
  728. * Clears all variables assigned to Zend_View either via {@link assign()} or
  729. * property overloading ({@link __set()}).
  730. *
  731. * @return void
  732. */
  733. public function clearVars()
  734. {
  735. $vars = get_object_vars($this);
  736. foreach ($vars as $key => $value) {
  737. if ('_' != substr($key, 0, 1)) {
  738. unset($this->$key);
  739. }
  740. }
  741. }
  742. /**
  743. * Processes a view script and returns the output.
  744. *
  745. * @param string $name The script script name to process.
  746. * @return string The script output.
  747. */
  748. public function render($name)
  749. {
  750. // find the script file name using the parent private method
  751. $this->_file = $this->_script($name);
  752. unset($name); // remove $name from local scope
  753. ob_start();
  754. $this->_run($this->_file);
  755. return $this->_filter(ob_get_clean()); // filter output
  756. }
  757. /**
  758. * Escapes a value for output in a view script.
  759. *
  760. * If escaping mechanism is one of htmlspecialchars or htmlentities, uses
  761. * {@link $_encoding} setting.
  762. *
  763. * @param mixed $var The output to escape.
  764. * @return mixed The escaped value.
  765. */
  766. public function escape($var)
  767. {
  768. if (in_array($this->_escape, array('htmlspecialchars', 'htmlentities'))) {
  769. return call_user_func($this->_escape, $var, ENT_COMPAT, $this->_encoding);
  770. }
  771. return call_user_func($this->_escape, $var);
  772. }
  773. /**
  774. * Set encoding to use with htmlentities() and htmlspecialchars()
  775. *
  776. * @param string $encoding
  777. * @return Zend_View_Abstract
  778. */
  779. public function setEncoding($encoding)
  780. {
  781. $this->_encoding = $encoding;
  782. return $this;
  783. }
  784. /**
  785. * Return current escape encoding
  786. *
  787. * @return string
  788. */
  789. public function getEncoding()
  790. {
  791. return $this->_encoding;
  792. }
  793. /**
  794. * Enable or disable strict vars
  795. *
  796. * If strict variables are enabled, {@link __get()} will raise a notice
  797. * when a variable is not defined.
  798. *
  799. * Use in conjunction with {@link Zend_View_Helper_DeclareVars the declareVars() helper}
  800. * to enforce strict variable handling in your view scripts.
  801. *
  802. * @param boolean $flag
  803. * @return Zend_View_Abstract
  804. */
  805. public function strictVars($flag = true)
  806. {
  807. $this->_strictVars = ($flag) ? true : false;
  808. return $this;
  809. }
  810. /**
  811. * Finds a view script from the available directories.
  812. *
  813. * @param $name string The base name of the script.
  814. * @return void
  815. */
  816. protected function _script($name)
  817. {
  818. if ($this->isLfiProtectionOn() && preg_match('#\.\.[\\\/]#', $name)) {
  819. require_once 'Zend/View/Exception.php';
  820. throw new Zend_View_Exception('Requested scripts may not include parent directory traversal ("../", "..\\" notation)');
  821. }
  822. if (0 == count($this->_path['script'])) {
  823. require_once 'Zend/View/Exception.php';
  824. throw new Zend_View_Exception('no view script directory set; unable to determine location for view script',
  825. $this);
  826. }
  827. foreach ($this->_path['script'] as $dir) {
  828. if (is_readable($dir . $name)) {
  829. return $dir . $name;
  830. }
  831. }
  832. require_once 'Zend/View/Exception.php';
  833. $message = "script '$name' not found in path ("
  834. . implode(PATH_SEPARATOR, $this->_path['script'])
  835. . ")";
  836. throw new Zend_View_Exception($message, $this);
  837. }
  838. /**
  839. * Applies the filter callback to a buffer.
  840. *
  841. * @param string $buffer The buffer contents.
  842. * @return string The filtered buffer.
  843. */
  844. private function _filter($buffer)
  845. {
  846. // loop through each filter class
  847. foreach ($this->_filter as $name) {
  848. // load and apply the filter class
  849. $filter = $this->getFilter($name);
  850. $buffer = call_user_func(array($filter, 'filter'), $buffer);
  851. }
  852. // done!
  853. return $buffer;
  854. }
  855. /**
  856. * Adds paths to the path stack in LIFO order.
  857. *
  858. * Zend_View::_addPath($type, 'dirname') adds one directory
  859. * to the path stack.
  860. *
  861. * Zend_View::_addPath($type, $array) adds one directory for
  862. * each array element value.
  863. *
  864. * In the case of filter and helper paths, $prefix should be used to
  865. * specify what class prefix to use with the given path.
  866. *
  867. * @param string $type The path type ('script', 'helper', or 'filter').
  868. * @param string|array $path The path specification.
  869. * @param string $prefix Class prefix to use with path (helpers and filters
  870. * only)
  871. * @return void
  872. */
  873. private function _addPath($type, $path, $prefix = null)
  874. {
  875. foreach ((array) $path as $dir) {
  876. // attempt to strip any possible separator and
  877. // append the system directory separator
  878. $dir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $dir);
  879. $dir = rtrim($dir, DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR)
  880. . DIRECTORY_SEPARATOR;
  881. switch ($type) {
  882. case 'script':
  883. // add to the top of the stack.
  884. array_unshift($this->_path[$type], $dir);
  885. break;
  886. case 'filter':
  887. case 'helper':
  888. default:
  889. // add as array with prefix and dir keys
  890. array_unshift($this->_path[$type], array('prefix' => $prefix, 'dir' => $dir));
  891. break;
  892. }
  893. }
  894. }
  895. /**
  896. * Resets the path stack for helpers and filters.
  897. *
  898. * @param string $type The path type ('helper' or 'filter').
  899. * @param string|array $path The directory (-ies) to set as the path.
  900. * @param string $classPrefix Class prefix to apply to elements of $path
  901. */
  902. private function _setPath($type, $path, $classPrefix = null)
  903. {
  904. $dir = DIRECTORY_SEPARATOR . ucfirst($type) . DIRECTORY_SEPARATOR;
  905. switch ($type) {
  906. case 'script':
  907. $this->_path[$type] = array(dirname(__FILE__) . $dir);
  908. $this->_addPath($type, $path);
  909. break;
  910. case 'filter':
  911. case 'helper':
  912. default:
  913. $this->_path[$type] = array(array(
  914. 'prefix' => 'Zend_View_' . ucfirst($type) . '_',
  915. 'dir' => dirname(__FILE__) . $dir
  916. ));
  917. $this->_addPath($type, $path, $classPrefix);
  918. break;
  919. }
  920. }
  921. /**
  922. * Return all paths for a given path type
  923. *
  924. * @param string $type The path type ('helper', 'filter', 'script')
  925. * @return array
  926. */
  927. private function _getPaths($type)
  928. {
  929. return $this->_path[$type];
  930. }
  931. /**
  932. * Register helper class as loaded
  933. *
  934. * @param string $name
  935. * @param string $class
  936. * @param string $file path to class file
  937. * @return void
  938. */
  939. private function _setHelperClass($name, $class, $file)
  940. {
  941. $this->_helperLoadedDir[$name] = $file;
  942. $this->_helperLoaded[$name] = $class;
  943. }
  944. /**
  945. * Register filter class as loaded
  946. *
  947. * @param string $name
  948. * @param string $class
  949. * @param string $file path to class file
  950. * @return void
  951. */
  952. private function _setFilterClass($name, $class, $file)
  953. {
  954. $this->_filterLoadedDir[$name] = $file;
  955. $this->_filterLoaded[$name] = $class;
  956. }
  957. /**
  958. * Add a prefixPath for a plugin type
  959. *
  960. * @param string $type
  961. * @param string $classPrefix
  962. * @param array $paths
  963. * @return Zend_View_Abstract
  964. */
  965. private function _addPluginPath($type, $classPrefix, array $paths)
  966. {
  967. $loader = $this->getPluginLoader($type);
  968. foreach ($paths as $path) {
  969. $loader->addPrefixPath($classPrefix, $path);
  970. }
  971. return $this;
  972. }
  973. /**
  974. * Get a path to a given plugin class of a given type
  975. *
  976. * @param string $type
  977. * @param string $name
  978. * @return string|false
  979. */
  980. private function _getPluginPath($type, $name)
  981. {
  982. $loader = $this->getPluginLoader($type);
  983. if ($loader->isLoaded($name)) {
  984. return $loader->getClassPath($name);
  985. }
  986. try {
  987. $loader->load($name);
  988. return $loader->getClassPath($name);
  989. } catch (Zend_Loader_Exception $e) {
  990. return false;
  991. }
  992. }
  993. /**
  994. * Retrieve a plugin object
  995. *
  996. * @param string $type
  997. * @param string $name
  998. * @return object
  999. */
  1000. private function _getPlugin($type, $name)
  1001. {
  1002. $name = ucfirst($name);
  1003. switch ($type) {
  1004. case 'filter':
  1005. $storeVar = '_filterClass';
  1006. $store = $this->_filterClass;
  1007. break;
  1008. case 'helper':
  1009. $storeVar = '_helper';
  1010. $store = $this->_helper;
  1011. break;
  1012. }
  1013. if (!isset($store[$name])) {
  1014. $class = $this->getPluginLoader($type)->load($name);
  1015. $store[$name] = new $class();
  1016. if (method_exists($store[$name], 'setView')) {
  1017. $store[$name]->setView($this);
  1018. }
  1019. }
  1020. $this->$storeVar = $store;
  1021. return $store[$name];
  1022. }
  1023. /**
  1024. * Use to include the view script in a scope that only allows public
  1025. * members.
  1026. *
  1027. * @return mixed
  1028. */
  1029. abstract protected function _run();
  1030. }