Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Convert Savant3 to pear2. Always throw exceptions, never load files i…

…nternally.
  • Loading branch information...
commit b6438c541c82c3abe6e3839333bf0abd055de4d5 0 parents
@saltybeagle saltybeagle authored
1  API-0.1.0
@@ -0,0 +1 @@
+Package PEAR2_Templates_Savant API release notes for version 0.1.0.
2  CREDITS
@@ -0,0 +1,2 @@
+;; put your info here
+Brett Bieber [saltybeagle] <saltybeagle@php.net> (lead)
5 README
@@ -0,0 +1,5 @@
+Savant is a powerful but lightweight object-oriented template system for PHP.
+
+Unlike other template systems, Savant by default does not compile your
+templates into PHP; instead, it uses PHP itself as its template language so you
+don't need to learn a new markup system.
4 RELEASE-0.1.0
@@ -0,0 +1,4 @@
+Port Savant3 to pear2.
+
+* Always throw exceptions.
+* Never load files internally.
22 extrasetup.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * This file is used to provide extra files/packages outside package.xml
+ */
+/**
+ * for example:
+if (basename(__DIR__) == 'trunk') {
+ $extrafiles = array(
+ new \pear2\Pyrus\Package(__DIR__ . '/../../HTTP_Request/trunk/package.xml'),
+ new \pear2\Pyrus\Package(__DIR__ . '/../../sandbox/Console_CommandLine/trunk/package.xml'),
+ new \pear2\Pyrus\Package(__DIR__ . '/../../MultiErrors/trunk/package.xml'),
+ new \pear2\Pyrus\Package(__DIR__ . '/../../Exception/trunk/package.xml'),
+ );
+} else {
+ $extrafiles = array(
+ new \pear2\Pyrus\Package(__DIR__ . '/../HTTP_Request/package.xml'),
+ new \pear2\Pyrus\Package(__DIR__ . '/../sandbox/Console_CommandLine/package.xml'),
+ new \pear2\Pyrus\Package(__DIR__ . '/../MultiErrors/package.xml'),
+ new \pear2\Pyrus\Package(__DIR__ . '/../Exception/package.xml'),
+ );
+}
+*/
51 package.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package version="2.1" xmlns="http://pear.php.net/dtd/package-2.1" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.1 http://pear.php.net/dtd/package-2.1.xsd">
+ <name>PEAR2_Templates_Savant</name>
+ <channel>pear2.php.net</channel>
+ <summary>Package PEAR2_Templates_Savant summary.
+</summary>
+ <description>
+Package detailed description here (found in README)</description>
+ <lead>
+ <name>Your Name</name>
+ <user>handle</user>
+ <email>handle@php.net</email>
+ <active>yes</active>
+ </lead>
+ <date>2009-08-09</date>
+ <time>18:45:47</time>
+ <version>
+ <release>0.1.0</release>
+ <api>0.1.0</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
+ <notes>Package PEAR2_Templates_Savant release notes for version 0.1.0.
+
+Package PEAR2_Templates_Savant API release notes for version 0.1.0.</notes>
+ <contents>
+ <dir name="/">
+ <dir name="src" baseinstalldir="pear2">
+ <dir name="Templates">
+ <dir name="Savant">
+ <file role="php" name="Main.php"/>
+ </dir>
+ </dir>
+ </dir>
+ </dir>
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5.2.0</min>
+ </php>
+ <pearinstaller>
+ <min>2.0.0a1</min>
+ </pearinstaller>
+ </required>
+ </dependencies>
+ <phprelease/>
+</package>
49 package_compatible.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package version="2.1" xmlns="http://pear.php.net/dtd/package-2.1" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.1 http://pear.php.net/dtd/package-2.1.xsd">
+ <name>PEAR2_Templates_Savant</name>
+ <channel>pear2.php.net</channel>
+ <summary>Package PEAR2_Templates_Savant summary.
+</summary>
+ <description>
+Package detailed description here (found in README)</description>
+ <lead>
+ <name>Your Name</name>
+ <user>handle</user>
+ <email>handle@php.net</email>
+ <active>yes</active>
+ </lead>
+ <date>2009-08-09</date>
+ <time>18:45:47</time>
+ <version>
+ <release>0.1.0</release>
+ <api>0.1.0</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
+ <notes>Package PEAR2_Templates_Savant release notes for version 0.1.0.
+
+Package PEAR2_Templates_Savant API release notes for version 0.1.0.</notes>
+ <contents>
+ <dir name="/">
+ <file role="php" name="php/pear2/Templates/Savant/Main.php"/>
+ </dir>
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5.2.0</min>
+ </php>
+ <pearinstaller>
+ <min>1.4.8</min>
+ </pearinstaller>
+ </required>
+ </dependencies>
+ <phprelease>
+ <filelist>
+ <install name="php/pear2/Templates/Savant/Main.php" as="pear2/Templates/Savant/Main.php"/>
+ </filelist>
+ </phprelease>
+</package>
17 packagexmlsetup.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Extra package.xml settings such as dependencies.
+ */
+/**
+ * for example:
+$package->dependencies['required']->package['pear2.php.net/PEAR2_Autoload']->save();
+$package->dependencies['required']->package['pear2.php.net/PEAR2_Exception']->save();
+$package->dependencies['required']->package['pear2.php.net/PEAR2_MultiErrors']->save();
+$package->dependencies['required']->package['pear2.php.net/PEAR2_HTTP_Request']->save();
+
+$compatible->dependencies['required']->package['pear2.php.net/PEAR2_Autoload']->save();
+$compatible->dependencies['required']->package['pear2.php.net/PEAR2_Exception']->save();
+$compatible->dependencies['required']->package['pear2.php.net/PEAR2_MultiErrors']->save();
+$compatible->dependencies['required']->package['pear2.php.net/PEAR2_HTTP_Request']->save();
+*/
+?>
8 src/Templates/Savant/Exception.php
@@ -0,0 +1,8 @@
+<?php
+namespace pear2\Templates\Savant;
+
+interface Exception extends \Exception
+{
+
+}
+?>
86 src/Templates/Savant/Filter.php
@@ -0,0 +1,86 @@
+<?php
+
+/**
+*
+* Abstract Savant3_Filter class.
+*
+* @package Savant3
+*
+* @author Paul M. Jones <pmjones@ciaweb.net>
+*
+* @license http://www.gnu.org/copyleft/lesser.html LGPL
+*
+* @version $Id: Filter.php,v 1.5 2005/04/29 16:23:50 pmjones Exp $
+*
+*/
+
+/**
+*
+* Abstract Savant3_Filter class.
+*
+* You have to extend this class for it to be useful; e.g., "class
+* Savant3_Filter_example extends Savant3_Filter".
+*
+* @package Savant3
+*
+* @author Paul M. Jones <pmjones@ciaweb.net>
+*
+*/
+namespace pear2\Templates\Savant;
+abstract class Filter
+{
+
+
+ /**
+ *
+ * Optional reference to the calling Savant object.
+ *
+ * @access protected
+ *
+ * @var object
+ *
+ */
+
+ protected $Savant = null;
+
+
+ /**
+ *
+ * Constructor.
+ *
+ * @access public
+ *
+ * @param array $conf An array of configuration keys and values for
+ * this filter.
+ *
+ * @return void
+ *
+ */
+
+ public function __construct($conf = null)
+ {
+ settype($conf, 'array');
+ foreach ($conf as $key => $val) {
+ $this->$key = $val;
+ }
+ }
+
+
+ /**
+ *
+ * Stub method for extended behaviors.
+ *
+ * @access public
+ *
+ * @param string $text The text buffer to filter.
+ *
+ * @return string The text buffer after it has been filtered.
+ *
+ */
+
+ public static function filter($text)
+ {
+ return $text;
+ }
+}
+?>
1,111 src/Templates/Savant/Main.php
@@ -0,0 +1,1111 @@
+<?php
+/**
+ * pear2\Templates\Savant\Main
+ *
+ * PHP version 5
+ *
+ * @category Yourcategory
+ * @package PEAR2_Templates_Savant
+ * @author Your Name <handle@php.net>
+ * @copyright 2009 Your Name
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @version SVN: $Id$
+ * @link http://svn.php.net/repository/pear2/PEAR2_Templates_Savant
+ */
+
+/**
+ * Main class for PEAR2_Templates_Savant
+ *
+ * @category Yourcategory
+ * @package PEAR2_Templates_Savant
+ * @author Your Name <handle@php.net>
+ * @copyright 2009 Your Name
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://svn.php.net/repository/pear2/PEAR2_Templates_Savant
+ */
+namespace pear2\Templates\Savant;
+class Main
+{
+ /**
+ *
+ * Array of configuration parameters.
+ *
+ * @access protected
+ *
+ * @var array
+ *
+ */
+
+ protected $__config = array(
+ 'template_path' => array(),
+ 'resource_path' => array(),
+ 'compiler' => null,
+ 'filters' => array(),
+ 'plugins' => array(),
+ 'template' => null,
+ 'plugin_conf' => array(),
+ 'extract' => false,
+ 'fetch' => null,
+ 'escape' => array('htmlspecialchars'),
+ );
+
+
+ // -----------------------------------------------------------------
+ //
+ // Constructor and magic methods
+ //
+ // -----------------------------------------------------------------
+
+
+ /**
+ *
+ * Constructor.
+ *
+ * @access public
+ *
+ * @param array $config An associative array of configuration keys for
+ * the Main object. Any, or none, of the keys may be set.
+ *
+ * @return pear2\Templates\Savant\Main A pear2\Templates\Savant\Main instance.
+ *
+ */
+
+ public function __construct($config = null)
+ {
+ // force the config to an array
+ settype($config, 'array');
+
+ // set the default template search path
+ if (isset($config['template_path'])) {
+ // user-defined dirs
+ $this->setPath('template', $config['template_path']);
+ } else {
+ // no directories set, use the
+ // default directory only
+ $this->setPath('template', null);
+ }
+
+ // set the default resource search path
+ if (isset($config['resource_path'])) {
+ // user-defined dirs
+ $this->setPath('resource', $config['resource_path']);
+ } else {
+ // no directories set, use the
+ // default directory only
+ $this->setPath('resource', null);
+ }
+
+ // set the extraction flag
+ if (isset($config['extract'])) {
+ $this->setExtract($config['extract']);
+ }
+
+ // set the exceptions flag
+ if (isset($config['exceptions'])) {
+ $this->setExceptions($config['exceptions']);
+ }
+
+ // set the template to use for output
+ if (isset($config['template'])) {
+ $this->setTemplate($config['template']);
+ }
+
+ // set the output escaping callbacks
+ if (isset($config['escape'])) {
+ $this->setEscape($config['escape']);
+ }
+
+ // set the default plugin configs
+ if (isset($config['plugin_conf']) && is_array($config['plugin_conf'])) {
+ foreach ($config['plugin_conf'] as $name => $opts) {
+ $this->setPluginConf($name, $opts);
+ }
+ }
+
+ // set the default filter callbacks
+ if (isset($config['filters'])) {
+ $this->addFilters($config['filters']);
+ }
+ }
+
+
+ /**
+ *
+ * Executes a main plugin method with arbitrary parameters.
+ *
+ * @access public
+ *
+ * @param string $func The plugin method name.
+ *
+ * @param array $args The parameters passed to the method.
+ *
+ * @return mixed The plugin output
+ *
+ */
+
+ public function __call($func, $args)
+ {
+ $plugin = $this->plugin($func);
+
+ // try to avoid the very-slow call_user_func_array()
+ // for plugins with very few parameters. thanks to
+ // Andreas Korthaus for profiling the code to find
+ // the slowdown.
+ switch (count($args)) {
+
+ case 0:
+ return $plugin->$func();
+
+ case 1:
+ return $plugin->$func($args[0]);
+ break;
+
+ case 2:
+ return $plugin->$func($args[0], $args[1]);
+ break;
+
+ case 3:
+ return $plugin->$func($args[0], $args[1], $args[2]);
+ break;
+
+ default:
+ return call_user_func_array(array($plugin, $func), $args);
+ break;
+ }
+ }
+
+
+ /**
+ *
+ * Magic method to echo this object as template output.
+ *
+ * Note that if there is an error, an exception will be thrown.
+ *
+ * @access public
+ *
+ * @return string The template output.
+ *
+ */
+
+ public function __toString()
+ {
+ return $this->getOutput();
+ }
+
+
+ /**
+ *
+ * Reports the API version for this class.
+ *
+ * @access public
+ *
+ * @return string A PHP-standard version number.
+ *
+ */
+
+ public function apiVersion()
+ {
+ return '@package_version@';
+ }
+
+
+ /**
+ *
+ * Returns an internal plugin object; creates it as needed.
+ *
+ * @access public
+ *
+ * @param string $name The plugin name. If this plugin has not
+ * been created yet, this method creates it automatically.
+ *
+ * @return mixed The plugin object.
+ *
+ */
+
+ public function plugin($name)
+ {
+ // shorthand reference
+ $plugins =& $this->__config['plugins'];
+
+ // is the plugin method object already instantiated?
+ if (! array_key_exists($name, $plugins)) {
+
+ // not already instantiated, so load it up.
+ // set up the class name.
+ $class = "pear2\Templates\Savant\Plugin\$name";
+
+ // get the default configuration for the plugin.
+ $plugin_conf =& $this->__config['plugin_conf'];
+ if (! empty($plugin_conf[$name])) {
+ $opts = $plugin_conf[$name];
+ } else {
+ $opts = array();
+ }
+
+ // add the Savant reference
+ $opts['Savant'] = $this;
+
+ // instantiate the plugin with its options.
+ $plugins[$name] = new $class($opts);
+ }
+
+ // return the plugin object
+ return $plugins[$name];
+ }
+
+
+ // -----------------------------------------------------------------
+ //
+ // Public configuration management (getters and setters).
+ //
+ // -----------------------------------------------------------------
+
+
+ /**
+ *
+ * Returns a copy of the Savant3 configuration parameters.
+ *
+ * @access public
+ *
+ * @param string $key The specific configuration key to return. If null,
+ * returns the entire configuration array.
+ *
+ * @return mixed A copy of the $this->__config array.
+ *
+ */
+
+ public function getConfig($key = null)
+ {
+ if (is_null($key)) {
+ // no key requested, return the entire config array
+ return $this->__config;
+ } elseif (empty($this->__config[$key])) {
+ // no such key
+ return null;
+ } else {
+ // return the requested key
+ return $this->__config[$key];
+ }
+ }
+
+
+ /**
+ *
+ * Sets a custom compiler/pre-processor callback for template sources.
+ *
+ * By default, Savant3 does not use a compiler; use this to set your
+ * own custom compiler (pre-processor) for template sources.
+ *
+ * @access public
+ *
+ * @param mixed $compiler A compiler callback value suitable for the
+ * first parameter of call_user_func(). Set to null/false/empty to
+ * use PHP itself as the template markup (i.e., no compiling).
+ *
+ * @return void
+ *
+ */
+
+ public function setCompiler($compiler)
+ {
+ $this->__config['compiler'] = $compiler;
+ }
+
+
+ /**
+ *
+ * Sets whether or not variables will be extracted.
+ *
+ * @access public
+ *
+ * @param bool $flag True to turn on variable extraction, false
+ * to turn it off.
+ *
+ * @return void
+ *
+ */
+
+ public function setExtract($flag)
+ {
+ $this->__config['extract'] = (bool) $flag;
+ }
+
+
+ /**
+ *
+ * Sets config array for a plugin.
+ *
+ * @access public
+ *
+ * @param string $plugin The plugin to configure.
+ *
+ * @param array $config The configuration array for the plugin.
+ *
+ * @return void
+ *
+ */
+
+ public function setPluginConf($plugin, $config = null)
+ {
+ $this->__config['plugin_conf'][$plugin] = $config;
+ }
+
+
+ /**
+ *
+ * Sets the template name to use.
+ *
+ * @access public
+ *
+ * @param string $template The template name.
+ *
+ * @return void
+ *
+ */
+
+ public function setTemplate($template)
+ {
+ $this->__config['template'] = $template;
+ }
+
+
+ // -----------------------------------------------------------------
+ //
+ // Output escaping and management.
+ //
+ // -----------------------------------------------------------------
+
+
+ /**
+ *
+ * Clears then sets the callbacks to use when calling $this->escape().
+ *
+ * Each parameter passed to this function is treated as a separate
+ * callback. For example:
+ *
+ * <code>
+ * $savant->setEscape(
+ * 'stripslashes',
+ * 'htmlspecialchars',
+ * array('StaticClass', 'method'),
+ * array($object, $method)
+ * );
+ * </code>
+ *
+ * @access public
+ *
+ * @return void
+ *
+ */
+
+ public function setEscape()
+ {
+ $this->__config['escape'] = (array) @func_get_args();
+ }
+
+
+ /**
+ *
+ * Adds to the callbacks used when calling $this->escape().
+ *
+ * Each parameter passed to this function is treated as a separate
+ * callback. For example:
+ *
+ * <code>
+ * $savant->addEscape(
+ * 'stripslashes',
+ * 'htmlspecialchars',
+ * array('StaticClass', 'method'),
+ * array($object, $method)
+ * );
+ * </code>
+ *
+ * @access public
+ *
+ * @return void
+ *
+ */
+
+ public function addEscape()
+ {
+ $args = (array) @func_get_args();
+ $this->__config['escape'] = array_merge(
+ $this->__config['escape'], $args
+ );
+ }
+
+
+ /**
+ *
+ * Gets the array of output-escaping callbacks.
+ *
+ * @access public
+ *
+ * @return array The array of output-escaping callbacks.
+ *
+ */
+
+ public function getEscape()
+ {
+ return $this->__config['escape'];
+ }
+
+
+ /**
+ *
+ * Applies escaping to a value.
+ *
+ * You can override the predefined escaping callbacks by passing
+ * added parameters as replacement callbacks.
+ *
+ * <code>
+ * // use predefined callbacks
+ * $result = $savant->escape($value);
+ *
+ * // use replacement callbacks
+ * $result = $savant->escape(
+ * $value,
+ * 'stripslashes',
+ * 'htmlspecialchars',
+ * array('StaticClass', 'method'),
+ * array($object, $method)
+ * );
+ * </code>
+ *
+ *
+ * Unfortunately, a call to "echo htmlspecialchars()" is twice
+ * as fast as a call to "echo $this->escape()" under the default
+ * escaping (which is htmlspecialchars). The benchmark showed
+ * 0.007 seconds for htmlspecialchars(), and 0.014 seconds for
+ * $this->escape(), on 300 calls each.
+ *
+ * @access public
+ *
+ * @param mixed $value The value to be escaped.
+ *
+ * @return mixed
+ *
+ */
+
+ public function escape($value)
+ {
+ // were custom callbacks passed?
+ if (func_num_args() == 1) {
+
+ // no, only a value was passed.
+ // loop through the predefined callbacks.
+ foreach ($this->__config['escape'] as $func) {
+ // this if() shaves 0.001sec off of 300 calls.
+ if (is_string($func)) {
+ $value = $func($value);
+ } else {
+ $value = call_user_func($func, $value);
+ }
+ }
+
+ } else {
+
+ // yes, use the custom callbacks
+ $callbacks = func_get_args();
+
+ // drop $value
+ array_shift($callbacks);
+
+ // loop through custom callbacks.
+ foreach ($callbacks as $func) {
+ // this if() shaves 0.001sec off of 300 calls.
+ if (is_string($func)) {
+ $value = $func($value);
+ } else {
+ $value = call_user_func($func, $value);
+ }
+ }
+
+ }
+
+ return $value;
+ }
+
+
+ /**
+ *
+ * Prints a value after escaping it for output.
+ *
+ * You can override the predefined escaping callbacks by passing
+ * added parameters as replacement callbacks.
+ *
+ * <code>
+ * // use predefined callbacks
+ * $this->eprint($value);
+ *
+ * // use replacement callbacks
+ * $this->eprint(
+ * $value,
+ * 'stripslashes',
+ * 'htmlspecialchars',
+ * array('StaticClass', 'method'),
+ * array($object, $method)
+ * );
+ * </code>
+ *
+ * @access public
+ *
+ * @param mixed $value The value to be escaped and printed.
+ *
+ * @return void
+ *
+ */
+
+ public function eprint($value)
+ {
+ // avoid the very slow call_user_func_array() when there
+ // are no custom escaping callbacks. thanks to
+ // Andreas Korthaus for profiling the code to find
+ // the slowdown.
+ $num = func_num_args();
+ if ($num == 1) {
+ echo $this->escape($value);
+ } else {
+ $args = func_get_args();
+ echo call_user_func_array(
+ array($this, 'escape'),
+ $args
+ );
+ }
+ }
+
+
+ // -----------------------------------------------------------------
+ //
+ // File management
+ //
+ // -----------------------------------------------------------------
+
+
+ /**
+ *
+ * Sets an entire array of search paths for templates or resources.
+ *
+ * @access public
+ *
+ * @param string $type The type of path to set, typically 'template'
+ * or 'resource'.
+ *
+ * @param string|array $path The new set of search paths. If null or
+ * false, resets to the current directory only.
+ *
+ * @return void
+ *
+ */
+
+ public function setPath($type, $path)
+ {
+ // clear out the prior search dirs
+ $this->__config[$type . '_path'] = array();
+
+ // always add the fallback directories as last resort
+ switch (strtolower($type)) {
+ case 'template':
+ // the current directory
+ $this->addPath($type, '.');
+ break;
+ case 'resource':
+ // the Savant3 distribution resources
+ $this->addPath($type, dirname(__FILE__) . '/Savant3/resources/');
+ break;
+ }
+
+ // actually add the user-specified directories
+ $this->addPath($type, $path);
+ }
+
+
+ /**
+ *
+ * Adds to the search path for templates and resources.
+ *
+ * @access public
+ *
+ * @param string|array $path The directory or stream to search.
+ *
+ * @return void
+ *
+ */
+
+ public function addPath($type, $path)
+ {
+ // convert from path string to array of directories
+ if (is_string($path) && ! strpos($path, '://')) {
+
+ // the path config is a string, and it's not a stream
+ // identifier (the "://" piece). add it as a path string.
+ $path = explode(PATH_SEPARATOR, $path);
+
+ // typically in path strings, the first one is expected
+ // to be searched first. however, Savant3 uses a stack,
+ // so the first would be last. reverse the path string
+ // so that it behaves as expected with path strings.
+ $path = array_reverse($path);
+
+ } else {
+
+ // just force to array
+ settype($path, 'array');
+
+ }
+
+ // loop through the path directories
+ foreach ($path as $dir) {
+
+ // no surrounding spaces allowed!
+ $dir = trim($dir);
+
+ // add trailing separators as needed
+ if (strpos($dir, '://') && substr($dir, -1) != '/') {
+ // stream
+ $dir .= '/';
+ } elseif (substr($dir, -1) != DIRECTORY_SEPARATOR) {
+ // directory
+ $dir .= DIRECTORY_SEPARATOR;
+ }
+
+ // add to the top of the search dirs
+ array_unshift(
+ $this->__config[$type . '_path'],
+ $dir
+ );
+ }
+ }
+
+
+ /**
+ *
+ * Searches the directory paths for a given file.
+ *
+ * @param array $type The type of path to search (template or resource).
+ *
+ * @param string $file The file name to look for.
+ *
+ * @return string|bool The full path and file name for the target file,
+ * or boolean false if the file is not found in any of the paths.
+ *
+ */
+
+ protected function findFile($type, $file)
+ {
+ // get the set of paths
+ $set = $this->__config[$type . '_path'];
+
+ // start looping through the path set
+ foreach ($set as $path) {
+
+ // get the path to the file
+ $fullname = $path . $file;
+
+ // is the path based on a stream?
+ if (strpos($path, '://') === false) {
+ // not a stream, so do a realpath() to avoid
+ // directory traversal attempts on the local file
+ // system. Suggested by Ian Eure, initially
+ // rejected, but then adopted when the secure
+ // compiler was added.
+ $path = realpath($path); // needed for substr() later
+ $fullname = realpath($fullname);
+ }
+
+ // the substr() check added by Ian Eure to make sure
+ // that the realpath() results in a directory registered
+ // with Savant so that non-registered directores are not
+ // accessible via directory traversal attempts.
+ if (file_exists($fullname) && is_readable($fullname) &&
+ substr($fullname, 0, strlen($path)) == $path) {
+ return $fullname;
+ }
+ }
+
+ // could not find the file in the set of paths
+ return false;
+ }
+
+
+ // -----------------------------------------------------------------
+ //
+ // Variable and reference assignment
+ //
+ // -----------------------------------------------------------------
+
+
+ /**
+ *
+ * Sets variables for the template (by copy).
+ *
+ * This method is overloaded; you can assign all the properties of
+ * an object, an associative array, or a single value by name.
+ *
+ * You are not allowed to assign any variable named '__config' as
+ * it would conflict with internal configuration tracking.
+ *
+ * In the following examples, the template will have two variables
+ * assigned to it; the variables will be known inside the template as
+ * "$this->var1" and "$this->var2".
+ *
+ * <code>
+ * $Savant3 = new Savant3();
+ *
+ * // assign by object
+ * $obj = new stdClass;
+ * $obj->var1 = 'something';
+ * $obj->var2 = 'else';
+ * $Savant3->assign($obj);
+ *
+ * // assign by associative array
+ * $ary = array('var1' => 'something', 'var2' => 'else');
+ * $Savant3->assign($ary);
+ *
+ * // assign by name and value
+ * $Savant3->assign('var1', 'something');
+ * $Savant3->assign('var2', 'else');
+ *
+ * // assign directly
+ * $Savant3->var1 = 'something';
+ * $Savant3->var2 = 'else';
+ * </code>
+ *
+ * @access public
+ *
+ * @return bool True on success, false on failure.
+ *
+ */
+
+ public function assign()
+ {
+ // get the arguments; there may be 1 or 2.
+ $arg0 = @func_get_arg(0);
+ $arg1 = @func_get_arg(1);
+
+ // assign from object
+ if (is_object($arg0)) {
+ // assign public properties
+ foreach (get_object_vars($arg0) as $key => $val) {
+ // can't assign to __config
+ if ($key != '__config') {
+ $this->$key = $val;
+ }
+ }
+ return true;
+ }
+
+ // assign from associative array
+ if (is_array($arg0)) {
+ foreach ($arg0 as $key => $val) {
+ // can't assign to __config
+ if ($key != '__config') {
+ $this->$key = $val;
+ }
+ }
+ return true;
+ }
+
+ // assign by name and value (can't assign to __config).
+ if (is_string($arg0) && func_num_args() > 1 && $arg0 != '__config') {
+ $this->$arg0 = $arg1;
+ return true;
+ }
+
+ // $arg0 was not object, array, or string.
+ return false;
+ }
+
+
+ /**
+ *
+ * Sets variables for the template (by reference).
+ *
+ * You are not allowed to assign any variable named '__config' as
+ * it would conflict with internal configuration tracking.
+ *
+ * <code>
+ * $Savant3 = new Savant3();
+ *
+ * // assign by name and value
+ * $Savant3->assignRef('var1', $ref);
+ *
+ * // assign directly
+ * $Savant3->ref =& $var1;
+ * </code>
+ *
+ * @access public
+ *
+ * @return bool True on success, false on failure.
+ *
+ */
+
+ public function assignRef($key, &$val)
+ {
+ // assign by name and reference (can't assign to __config).
+ if ($key != '__config') {
+ $this->$key =& $val;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ // -----------------------------------------------------------------
+ //
+ // Template processing
+ //
+ // -----------------------------------------------------------------
+
+
+ /**
+ *
+ * Displays a template directly (equivalent to <code>echo $tpl</code>).
+ *
+ * @access public
+ *
+ * @param string $tpl The template source to compile and display.
+ *
+ * @return void
+ *
+ */
+
+ public function display($tpl = null)
+ {
+ echo $this->getOutput($tpl);
+ }
+
+ /**
+ * Returns output, including error_text if an error occurs.
+ *
+ * @param $tpl The template to process; if null, uses the
+ * default template set with setTemplate().
+ *
+ * @return string The template output.
+ */
+ public function getOutput($tpl = null)
+ {
+ $output = $this->fetch($tpl);
+ return $output;
+ }
+
+
+ /**
+ *
+ * Compiles, executes, and filters a template source.
+ *
+ * @access public
+ *
+ * @param string $tpl The template to process; if null, uses the
+ * default template set with setTemplate().
+ *
+ * @return mixed The template output string.
+ *
+ */
+
+ public function fetch($tpl = null)
+ {
+ // make sure we have a template source to work with
+ if (is_null($tpl)) {
+ $tpl = $this->__config['template'];
+ }
+
+ // get a path to the compiled template script
+ $result = $this->template($tpl);
+
+ // did we get a path?
+ if (!$result) {
+
+ // no. return the error result.
+ return $result;
+
+ } else {
+
+ // yes. execute the template script. move the script-path
+ // out of the local scope, then clean up the local scope to
+ // avoid variable name conflicts.
+ $this->__config['fetch'] = $result;
+ unset($result);
+ unset($tpl);
+
+ // are we doing extraction?
+ if ($this->__config['extract']) {
+ // pull variables into the local scope.
+ extract(get_object_vars($this), EXTR_REFS);
+ }
+
+ // buffer output so we can return it instead of displaying.
+ ob_start();
+
+ // are we using filters?
+ if ($this->__config['filters']) {
+ // use a second buffer to apply filters. we used to set
+ // the ob_start() filter callback, but that would
+ // silence errors in the filters. Hendy Irawan provided
+ // the next three lines as a "verbose" fix.
+ ob_start();
+ include $this->__config['fetch'];
+ echo $this->applyFilters(ob_get_clean());
+ } else {
+ // no filters being used.
+ include $this->__config['fetch'];
+ }
+
+ // reset the fetch script value, get the buffer, and return.
+ $this->__config['fetch'] = null;
+ return ob_get_clean();
+ }
+ }
+
+
+ /**
+ *
+ * Compiles a template and returns path to compiled script.
+ *
+ * By default, Savant does not compile templates, it uses PHP as the
+ * markup language, so the "compiled" template is the same as the source
+ * template.
+ *
+ * Used inside a template script like so:
+ *
+ * <code>
+ * include $this->template($tpl);
+ * </code>
+ *
+ * @access protected
+ *
+ * @param string $tpl The template source name to look for.
+ *
+ * @return string The full path to the compiled template script.
+ *
+ * @throws object An error object with a 'ERR_TEMPLATE' code.
+ *
+ */
+
+ protected function template($tpl = null)
+ {
+ // set to default template if none specified.
+ if (is_null($tpl)) {
+ $tpl = $this->__config['template'];
+ }
+
+ // find the template source.
+ $file = $this->findFile('template', $tpl);
+ if (! $file) {
+ throw new Exception('Template error. The template, '.$tpl.', was not found.');
+ }
+
+ // are we compiling source into a script?
+ if ($this->__config['compiler']) {
+ // compile the template source and get the path to the
+ // compiled script (will be returned instead of the
+ // source path)
+ $result = call_user_func(
+ array($this->__config['compiler'], 'compile'),
+ $file
+ );
+ } else {
+ // no compiling requested, use the source path
+ $result = $file;
+ }
+
+ // is there a script from the compiler?
+ if (!$result) {
+ // return an error, along with any error info
+ // generated by the compiler.
+ throw new Exception('Compiler error for template '.$tpl.'. '.$result );
+
+ } else {
+ // no errors, the result is a path to a script
+ return $result;
+ }
+ }
+
+
+ // -----------------------------------------------------------------
+ //
+ // Filter management and processing
+ //
+ // -----------------------------------------------------------------
+
+
+ /**
+ *
+ * Resets the filter stack to the provided list of callbacks.
+ *
+ * @access protected
+ *
+ * @param array An array of filter callbacks.
+ *
+ * @return void
+ *
+ */
+
+ public function setFilters()
+ {
+ $this->__config['filters'] = (array) @func_get_args();
+ }
+
+
+ /**
+ *
+ * Adds filter callbacks to the stack of filters.
+ *
+ * @access protected
+ *
+ * @param array An array of filter callbacks.
+ *
+ * @return void
+ *
+ */
+
+ public function addFilters()
+ {
+ // add the new filters to the static config variable
+ // via the reference
+ foreach ((array) @func_get_args() as $callback) {
+ $this->__config['filters'][] = $callback;
+ }
+ }
+
+
+ /**
+ *
+ * Runs all filter callbacks on buffered output.
+ *
+ * @access protected
+ *
+ * @param string The template output.
+ *
+ * @return void
+ *
+ */
+
+ protected function applyFilters($buffer)
+ {
+ foreach ($this->__config['filters'] as $callback) {
+
+ // if the callback is a static Savant3_Filter method,
+ // and not already loaded, try to auto-load it.
+ if (is_array($callback) &&
+ is_string($callback[0]) &&
+ substr($callback[0], 0, 15) == 'Savant3_Filter_' &&
+ ! class_exists($callback[0])) {
+
+ // load the Savant3_Filter_*.php resource
+ $file = $callback[0] . '.php';
+ $result = $this->findFile('resource', $file);
+ if ($result) {
+ include_once $result;
+ }
+ }
+
+ // can't pass a third $this param, it chokes the OB system.
+ $buffer = call_user_func($callback, $buffer);
+ }
+
+ return $buffer;
+ }
+
+}
68 src/Templates/Savant/Plugin.php
@@ -0,0 +1,68 @@
+<?php
+
+/**
+*
+* Abstract Savant3_Plugin class.
+*
+* @package Savant3
+*
+* @author Paul M. Jones <pmjones@ciaweb.net>
+*
+* @license http://www.gnu.org/copyleft/lesser.html LGPL
+*
+* @version $Id: Plugin.php,v 1.5 2005/04/29 16:23:50 pmjones Exp $
+*
+*/
+
+/**
+*
+* Abstract Savant3_Plugin class.
+*
+* You have to extend this class for it to be useful; e.g., "class
+* Savant3_Plugin_example extends Savant2_Plugin". Be sure to add a
+* method named for the plugin itself; e.g., "function example()".
+*
+* @package Savant3
+*
+* @author Paul M. Jones <pmjones@ciaweb.net>
+*
+*/
+namespace pear2\Templates\Savant;
+abstract class Plugin
+{
+
+ /**
+ *
+ * Reference to the calling Savant object.
+ *
+ * @access protected
+ *
+ * @var object
+ *
+ */
+
+ protected $Savant = null;
+
+
+ /**
+ *
+ * Constructor.
+ *
+ * @access public
+ *
+ * @param array $conf An array of configuration keys and values for
+ * this plugin.
+ *
+ * @return void
+ *
+ */
+
+ public function __construct($conf = null)
+ {
+ settype($conf, 'array');
+ foreach ($conf as $key => $val) {
+ $this->$key = $val;
+ }
+ }
+}
+?>
51 stub.php
@@ -0,0 +1,51 @@
+#!/usr/bin/env php
+<?php
+/**
+ * If your package does special stuff in phar format, use this file. Remove if
+ * no phar format is ever generated
+ */
+if (version_compare(phpversion(), '5.3.1', '<')) {
+ if (substr(phpversion(), 0, 5) != '5.3.1') {
+ // this small hack is because of running RCs of 5.3.1
+ echo "PEAR2_Templates_Savant requires PHP 5.3.1 or newer.
+";
+ exit -1;
+ }
+}
+foreach (array('phar', 'spl', 'pcre', 'simplexml') as $ext) {
+ if (!extension_loaded($ext)) {
+ echo 'Extension ', $ext, " is required
+";
+ exit -1;
+ }
+}
+try {
+ Phar::mapPhar();
+} catch (Exception $e) {
+ echo "Cannot process PEAR2_Templates_Savant phar:
+";
+ echo $e->getMessage(), "
+";
+ exit -1;
+}
+function PEAR2_Templates_Savant_autoload($class)
+{
+ $class = str_replace('_', '\', $class);
+ if (file_exists('phar://' . __FILE__ . '/PEAR2_Templates_Savant-0.1.0/php/' . implode('/', explode('\', $class)) . '.php')) {
+ include 'phar://' . __FILE__ . '/PEAR2_Templates_Savant-0.1.0/php/' . implode('/', explode('\', $class)) . '.php';
+ }
+}
+spl_autoload_register("PEAR2_Templates_Savant_autoload");
+$phar = new Phar(__FILE__);
+$sig = $phar->getSignature();
+define('PEAR2_Templates_Savant_SIG', $sig['hash']);
+define('PEAR2_Templates_Savant_SIGTYPE', $sig['hash_type']);
+
+// your package-specific stuff here, for instance, here is what Pyrus does:
+
+/**
+ * $frontend = new \pear2\Pyrus\ScriptFrontend\Commands;
+ * @array_shift($_SERVER['argv']);
+ * $frontend->run($_SERVER['argv']);
+ */
+__HALT_COMPILER();
Please sign in to comment.
Something went wrong with that request. Please try again.