| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860 | <?php/** * Smarty Resource Plugin * * @package Smarty * @subpackage TemplateResources * @author Rodney Rehm *//** * Smarty Resource Plugin * * Base implementation for resource plugins * * @package Smarty * @subpackage TemplateResources */abstract class Smarty_Resource {    /**     * cache for Smarty_Template_Source instances     * @var array     */    public static $sources = array();    /**     * cache for Smarty_Template_Compiled instances     * @var array     */    public static $compileds = array();    /**     * cache for Smarty_Resource instances     * @var array     */    public static $resources = array();    /**     * resource types provided by the core     * @var array     */    protected static $sysplugins = array(        'file' => true,        'string' => true,        'extends' => true,        'stream' => true,        'eval' => true,        'php' => true    );    /**     * Name of the Class to compile this resource's contents with     * @var string     */    public $compiler_class = 'Smarty_Internal_SmartyTemplateCompiler';    /**     * Name of the Class to tokenize this resource's contents with     * @var string     */    public $template_lexer_class = 'Smarty_Internal_Templatelexer';    /**     * Name of the Class to parse this resource's contents with     * @var string     */    public $template_parser_class = 'Smarty_Internal_Templateparser';    /**     * Load template's source into current template object     *     * {@internal The loaded source is assigned to $_template->source->content directly.}}     *     * @param Smarty_Template_Source $source source object     * @return string template source     * @throws SmartyException if source cannot be loaded     */    public abstract function getContent(Smarty_Template_Source $source);    /**     * populate Source Object with meta data from Resource     *     * @param Smarty_Template_Source   $source source object     * @param Smarty_Internal_Template $_template     template object     */    public abstract function populate(Smarty_Template_Source $source, Smarty_Internal_Template $_template=null);    /**     * populate Source Object with timestamp and exists from Resource     *     * @param Smarty_Template_Source $source source object     */    public function populateTimestamp(Smarty_Template_Source $source)    {        // intentionally left blank    }    /**     * modify resource_name according to resource handlers specifications     *     * @param Smarty $smarty        Smarty instance     * @param string $resource_name resource_name to make unique     * @return string unique resource name     */    protected function buildUniqueResourceName(Smarty $smarty, $resource_name)    {        return get_class($this) . '#' . $smarty->joined_template_dir . '#' . $resource_name;    }    /**     * populate Compiled Object with compiled filepath     *     * @param Smarty_Template_Compiled $compiled  compiled object     * @param Smarty_Internal_Template $_template template object     */    public function populateCompiledFilepath(Smarty_Template_Compiled $compiled, Smarty_Internal_Template $_template)    {        $_compile_id = isset($_template->compile_id) ? preg_replace('![^\w\|]+!', '_', $_template->compile_id) : null;        $_filepath = $compiled->source->uid;        // if use_sub_dirs, break file into directories        if ($_template->smarty->use_sub_dirs) {            $_filepath = substr($_filepath, 0, 2) . DS             . substr($_filepath, 2, 2) . DS             . substr($_filepath, 4, 2) . DS             . $_filepath;        }        $_compile_dir_sep = $_template->smarty->use_sub_dirs ? DS : '^';        if (isset($_compile_id)) {            $_filepath = $_compile_id . $_compile_dir_sep . $_filepath;        }        // caching token        if ($_template->caching) {            $_cache = '.cache';        } else {            $_cache = '';        }        $_compile_dir = $_template->smarty->getCompileDir();        // set basename if not specified        $_basename = $this->getBasename($compiled->source);        if ($_basename === null) {            $_basename = basename( preg_replace('![^\w\/]+!', '_', $compiled->source->name) );        }        // separate (optional) basename by dot        if ($_basename) {            $_basename = '.' . $_basename;        }        $compiled->filepath = $_compile_dir . $_filepath . '.' . $compiled->source->type . $_basename . $_cache . '.php';    }        /**     * Normalize Paths "foo/../bar" to "bar"      *     * @param string $_path path to normalize     * @param boolean $ds respect windows directory separator     * @return string normalized path     */    protected function normalizePath($_path, $ds=true)    {        if ($ds) {            // don't we all just love windows?            $_path = str_replace('\\', '/', $_path);        }                // resolve simples        $_path = preg_replace('#(/\./(\./)*)|/{2,}#', '/', $_path);        // resolve parents        while (true) {            $_parent = strpos($_path, '/../');            if ($_parent === false) {                break;            } else if ($_parent === 0) {                $_path = substr($_path, 3);                break;            }                        $_pos = strrpos($_path, '/', $_parent - strlen($_path) - 1);            if ($_pos === false) {                // don't we all just love windows?                $_pos = $_parent;            }                        $_path = substr_replace($_path, '', $_pos, $_parent + 3 - $_pos);        }                if ($ds && DS != '/') {            // don't we all just love windows?            $_path = str_replace('/', '\\', $_path);        }                return $_path;    }        /**     * build template filepath by traversing the template_dir array     *     * @param Smarty_Template_Source   $source    source object     * @param Smarty_Internal_Template $_template template object     * @return string fully qualified filepath     * @throws SmartyException if default template handler is registered but not callable     */    protected function buildFilepath(Smarty_Template_Source $source, Smarty_Internal_Template $_template=null)    {        $file = $source->name;        if ($source instanceof Smarty_Config_Source) {            $_directories = $source->smarty->getConfigDir();            $_default_handler = $source->smarty->default_config_handler_func;        } else {            $_directories = $source->smarty->getTemplateDir();            $_default_handler = $source->smarty->default_template_handler_func;        }        // go relative to a given template?        $_file_is_dotted = $file[0] == '.' && ($file[1] == '.' || $file[1] == '/' || $file[1] == "\\");        if ($_template && $_template->parent instanceof Smarty_Internal_Template && $_file_is_dotted) {            if ($_template->parent->source->type != 'file' && $_template->parent->source->type != 'extends' && !$_template->parent->allow_relative_path) {                throw new SmartyException("Template '{$file}' cannot be relative to template of resource type '{$_template->parent->source->type}'");            }            $file = dirname($_template->parent->source->filepath) . DS . $file;            $_file_exact_match = true;            if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $file)) {                // the path gained from the parent template is relative to the current working directory                // as expansions (like include_path) have already been done                $file = getcwd() . DS . $file;            }        }        // resolve relative path        if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $file)) {            // don't we all just love windows?            $_path = str_replace('\\', '/', $file);            $_was_relative_prefix = $file[0] == '.' ? substr($file, 0, strpos($_path, '/')) : null;            $_path = DS . trim($file, '/');            $_was_relative = true;        } else {            // don't we all just love windows?            $_path = str_replace('\\', '/', $file);        }        $_path = $this->normalizePath($_path, false);        if (DS != '/') {            // don't we all just love windows?            $_path = str_replace('/', '\\', $_path);        }        // revert to relative        if (isset($_was_relative)) {            if (isset($_was_relative_prefix)){                $_path = $_was_relative_prefix . $_path;            } else {                $_path = substr($_path, 1);            }        }        // this is only required for directories        $file = rtrim($_path, '/\\');        // files relative to a template only get one shot        if (isset($_file_exact_match)) {            return $this->fileExists($source, $file) ? $file : false;        }        // template_dir index?        if (preg_match('#^\[(?P<key>[^\]]+)\](?P<file>.+)$#', $file, $match)) {            $_directory = null;            // try string indexes            if (isset($_directories[$match['key']])) {                $_directory = $_directories[$match['key']];            } else if (is_numeric($match['key'])) {                // try numeric index                $match['key'] = (int) $match['key'];                if (isset($_directories[$match['key']])) {                    $_directory = $_directories[$match['key']];                } else {                    // try at location index                    $keys = array_keys($_directories);                    $_directory = $_directories[$keys[$match['key']]];                }            }            if ($_directory) {                $_file = substr($file, strpos($file, ']') + 1);                $_filepath = $_directory . $_file;                if ($this->fileExists($source, $_filepath)) {                    return $_filepath;                }            }        }        $_stream_resolve_include_path = function_exists('stream_resolve_include_path');        // relative file name?        if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $file)) {            foreach ($_directories as $_directory) {                $_filepath = $_directory . $file;                if ($this->fileExists($source, $_filepath)) {                    return $this->normalizePath($_filepath);                }                if ($source->smarty->use_include_path && !preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_directory)) {                    // try PHP include_path                    if ($_stream_resolve_include_path) {                        $_filepath = stream_resolve_include_path($_filepath);                    } else {                        $_filepath = Smarty_Internal_Get_Include_Path::getIncludePath($_filepath);                    }                    if ($_filepath !== false) {                        if ($this->fileExists($source, $_filepath)) {                            return $this->normalizePath($_filepath);                        }                    }                }            }        }        // try absolute filepath        if ($this->fileExists($source, $file)) {            return $file;        }        // no tpl file found        if ($_default_handler) {            if (!is_callable($_default_handler)) {                if ($source instanceof Smarty_Config_Source) {                    throw new SmartyException("Default config handler not callable");                } else {                    throw new SmartyException("Default template handler not callable");                }            }            $_return = call_user_func_array($_default_handler,                array($source->type, $source->name, &$_content, &$_timestamp, $source->smarty));            if (is_string($_return)) {                $source->timestamp = @filemtime($_return);                $source->exists = !!$source->timestamp;                return $_return;            } elseif ($_return === true) {                $source->content = $_content;                $source->timestamp = $_timestamp;                $source->exists = true;                return $_filepath;            }        }        // give up        return false;    }    /**     * test is file exists and save timestamp     *     * @param Smarty_Template_Source   $source    source object     * @param string $file file name     * @return bool  true if file exists     */    protected function fileExists(Smarty_Template_Source $source, $file)    {        $source->timestamp = @filemtime($file);        return $source->exists = !!$source->timestamp;    }    /**     * Determine basename for compiled filename     *     * @param Smarty_Template_Source $source source object     * @return string resource's basename     */    protected function getBasename(Smarty_Template_Source $source)    {        return null;    }    /**     * Load Resource Handler     *     * @param Smarty $smarty    smarty object     * @param string $type      name of the resource     * @return Smarty_Resource Resource Handler     */    public static function load(Smarty $smarty, $type)    {        // try smarty's cache        if (isset($smarty->_resource_handlers[$type])) {            return $smarty->_resource_handlers[$type];        }        // try registered resource        if (isset($smarty->registered_resources[$type])) {            if ($smarty->registered_resources[$type] instanceof Smarty_Resource) {                $smarty->_resource_handlers[$type] = $smarty->registered_resources[$type];                // note registered to smarty is not kept unique!                return $smarty->_resource_handlers[$type];            }            if (!isset(self::$resources['registered'])) {                self::$resources['registered'] = new Smarty_Internal_Resource_Registered();            }            if (!isset($smarty->_resource_handlers[$type])) {                $smarty->_resource_handlers[$type] = self::$resources['registered'];            }            return $smarty->_resource_handlers[$type];        }        // try sysplugins dir        if (isset(self::$sysplugins[$type])) {            if (!isset(self::$resources[$type])) {                $_resource_class = 'Smarty_Internal_Resource_' . ucfirst($type);                self::$resources[$type] = new $_resource_class();            }            return $smarty->_resource_handlers[$type] = self::$resources[$type];        }        // try plugins dir        $_resource_class = 'Smarty_Resource_' . ucfirst($type);        if ($smarty->loadPlugin($_resource_class)) {            if (isset(self::$resources[$type])) {                return $smarty->_resource_handlers[$type] = self::$resources[$type];            }            if (class_exists($_resource_class, false)) {                self::$resources[$type] = new $_resource_class();                return $smarty->_resource_handlers[$type] = self::$resources[$type];            } else {                $smarty->registerResource($type, array(                    "smarty_resource_{$type}_source",                    "smarty_resource_{$type}_timestamp",                    "smarty_resource_{$type}_secure",                    "smarty_resource_{$type}_trusted"                ));                // give it another try, now that the resource is registered properly                return self::load($smarty, $type);            }        }        // try streams        $_known_stream = stream_get_wrappers();        if (in_array($type, $_known_stream)) {            // is known stream            if (is_object($smarty->security_policy)) {                $smarty->security_policy->isTrustedStream($type);            }            if (!isset(self::$resources['stream'])) {                self::$resources['stream'] = new Smarty_Internal_Resource_Stream();            }            return $smarty->_resource_handlers[$type] = self::$resources['stream'];        }        // TODO: try default_(template|config)_handler        // give up        throw new SmartyException("Unkown resource type '{$type}'");    }    /**     * extract resource_type and resource_name from template_resource and config_resource     *     * @note "C:/foo.tpl" was forced to file resource up till Smarty 3.1.3 (including).     * @param string  $resource_name    template_resource or config_resource to parse     * @param string  $default_resource the default resource_type defined in $smarty     * @param string &$name             the parsed resource name     * @param string &$type             the parsed resource type     * @return void     */    protected static function parseResourceName($resource_name, $default_resource, &$name, &$type)    {        $parts = explode(':', $resource_name, 2);        if (!isset($parts[1]) || !isset($parts[0][1])) {            // no resource given, use default            // or single character before the colon is not a resource type, but part of the filepath            $type = $default_resource;            $name = $resource_name;        } else {            $type = $parts[0];            $name = $parts[1];        }    }    /**     * modify resource_name according to resource handlers specifications     *     * @param Smarty $smarty        Smarty instance     * @param string $resource_name resource_name to make unique     * @return string unique resource name     */    /**     * modify template_resource according to resource handlers specifications     *     * @param string $smarty            Smarty instance     * @param string $template_resource template_resource to extracate resource handler and name of     * @return string unique resource name     */    public static function getUniqueTemplateName($smarty, $template_resource)    {        self::parseResourceName($template_resource, $smarty->default_resource_type, $name, $type);        // TODO: optimize for Smarty's internal resource types        $resource = Smarty_Resource::load($smarty, $type);        return $resource->buildUniqueResourceName($smarty, $name);    }    /**     * initialize Source Object for given resource     *     * Either [$_template] or [$smarty, $template_resource] must be specified     *     * @param Smarty_Internal_Template $_template         template object     * @param Smarty                   $smarty            smarty object     * @param string                   $template_resource resource identifier     * @return Smarty_Template_Source Source Object     */    public static function source(Smarty_Internal_Template $_template=null, Smarty $smarty=null, $template_resource=null)    {        if ($_template) {            $smarty = $_template->smarty;            $template_resource = $_template->template_resource;        }        // parse resource_name, load resource handler, identify unique resource name        self::parseResourceName($template_resource, $smarty->default_resource_type, $name, $type);        $resource = Smarty_Resource::load($smarty, $type);        $unique_resource_name = $resource->buildUniqueResourceName($smarty, $name);        // check runtime cache        $_cache_key = 'template|' . $unique_resource_name;        if ($smarty->compile_id) {            $_cache_key .= '|'.$smarty->compile_id;        }        if (isset(self::$sources[$_cache_key])) {            return self::$sources[$_cache_key];        }        // create source        $source = new Smarty_Template_Source($resource, $smarty, $template_resource, $type, $name, $unique_resource_name);        $resource->populate($source, $_template);        // runtime cache        self::$sources[$_cache_key] = $source;        return $source;    }    /**     * initialize Config Source Object for given resource     *     * @param Smarty_Internal_Config $_config config object     * @return Smarty_Config_Source Source Object     */    public static function config(Smarty_Internal_Config $_config)    {        static $_incompatible_resources = array('eval' => true, 'string' => true, 'extends' => true, 'php' => true);        $config_resource = $_config->config_resource;        $smarty = $_config->smarty;        // parse resource_name        self::parseResourceName($config_resource, $smarty->default_config_type, $name, $type);        // make sure configs are not loaded via anything smarty can't handle        if (isset($_incompatible_resources[$type])) {            throw new SmartyException ("Unable to use resource '{$type}' for config");        }        // load resource handler, identify unique resource name        $resource = Smarty_Resource::load($smarty, $type);        $unique_resource_name = $resource->buildUniqueResourceName($smarty, $name);        // check runtime cache        $_cache_key = 'config|' . $unique_resource_name;        if (isset(self::$sources[$_cache_key])) {            return self::$sources[$_cache_key];        }        // create source        $source = new Smarty_Config_Source($resource, $smarty, $config_resource, $type, $name, $unique_resource_name);        $resource->populate($source, null);        // runtime cache        self::$sources[$_cache_key] = $source;        return $source;    }}/** * Smarty Resource Data Object * * Meta Data Container for Template Files * * @package Smarty * @subpackage TemplateResources * @author Rodney Rehm * * @property integer $timestamp Source Timestamp * @property boolean $exists    Source Existance * @property boolean $template  Extended Template reference * @property string  $content   Source Content */class Smarty_Template_Source {    /**     * Name of the Class to compile this resource's contents with     * @var string     */    public $compiler_class = null;    /**     * Name of the Class to tokenize this resource's contents with     * @var string     */    public $template_lexer_class = null;    /**     * Name of the Class to parse this resource's contents with     * @var string     */    public $template_parser_class = null;    /**     * Unique Template ID     * @var string     */    public $uid = null;    /**     * Template Resource (Smarty_Internal_Template::$template_resource)     * @var string     */    public $resource = null;    /**     * Resource Type     * @var string     */    public $type = null;    /**     * Resource Name     * @var string     */    public $name = null;    /**     * Unique Resource Name     * @var string     */    public $unique_resource = null;    /**     * Source Filepath     * @var string     */    public $filepath = null;    /**     * Source is bypassing compiler     * @var boolean     */    public $uncompiled = null;    /**     * Source must be recompiled on every occasion     * @var boolean     */    public $recompiled = null;    /**     * The Components an extended template is made of     * @var array     */    public $components = null;    /**     * Resource Handler     * @var Smarty_Resource     */    public $handler = null;    /**     * Smarty instance     * @var Smarty     */    public $smarty = null;    /**     * create Source Object container     *     * @param Smarty_Resource $handler          Resource Handler this source object communicates with     * @param Smarty          $smarty           Smarty instance this source object belongs to     * @param string          $resource         full template_resource     * @param string          $type             type of resource     * @param string          $name             resource name     * @param string          $unique_resource  unqiue resource name     */    public function __construct(Smarty_Resource $handler, Smarty $smarty, $resource, $type, $name, $unique_resource)    {        $this->handler = $handler; // Note: prone to circular references        $this->compiler_class = $handler->compiler_class;        $this->template_lexer_class = $handler->template_lexer_class;        $this->template_parser_class = $handler->template_parser_class;        $this->uncompiled = $this->handler instanceof Smarty_Resource_Uncompiled;        $this->recompiled = $this->handler instanceof Smarty_Resource_Recompiled;        $this->smarty = $smarty;        $this->resource = $resource;        $this->type = $type;        $this->name = $name;        $this->unique_resource = $unique_resource;    }    /**     * get a Compiled Object of this source     *     * @param Smarty_Internal_Template $_template template objet     * @return Smarty_Template_Compiled compiled object     */    public function getCompiled(Smarty_Internal_Template $_template)    {        // check runtime cache        $_cache_key = $this->unique_resource . '#' . $_template->compile_id;        if (isset(Smarty_Resource::$compileds[$_cache_key])) {            return Smarty_Resource::$compileds[$_cache_key];        }        $compiled = new Smarty_Template_Compiled($this);        $this->handler->populateCompiledFilepath($compiled, $_template);        $compiled->timestamp = @filemtime($compiled->filepath);        $compiled->exists = !!$compiled->timestamp;        // runtime cache        Smarty_Resource::$compileds[$_cache_key] = $compiled;        return $compiled;    }    /**     * render the uncompiled source     *     * @param Smarty_Internal_Template $_template template object     */    public function renderUncompiled(Smarty_Internal_Template $_template)    {        return $this->handler->renderUncompiled($this, $_template);    }    /**     * <<magic>> Generic Setter.     *     * @param string $property_name valid: timestamp, exists, content, template     * @param mixed  $value        new value (is not checked)     * @throws SmartyException if $property_name is not valid     */    public function __set($property_name, $value)    {        switch ($property_name) {            // regular attributes            case 'timestamp':            case 'exists':            case 'content':            // required for extends: only            case 'template':                $this->$property_name = $value;                break;            default:                throw new SmartyException("invalid source property '$property_name'.");        }    }    /**     * <<magic>> Generic getter.     *     * @param string $property_name valid: timestamp, exists, content     * @return mixed     * @throws SmartyException if $property_name is not valid     */    public function __get($property_name)    {        switch ($property_name) {            case 'timestamp':            case 'exists':                $this->handler->populateTimestamp($this);                return $this->$property_name;            case 'content':                return $this->content = $this->handler->getContent($this);            default:                throw new SmartyException("source property '$property_name' does not exist.");        }    }}/** * Smarty Resource Data Object * * Meta Data Container for Template Files * * @package Smarty * @subpackage TemplateResources * @author Rodney Rehm * * @property string $content compiled content */class Smarty_Template_Compiled {    /**     * Compiled Filepath     * @var string     */    public $filepath = null;    /**     * Compiled Timestamp     * @var integer     */    public $timestamp = null;    /**     * Compiled Existance     * @var boolean     */    public $exists = false;    /**     * Compiled Content Loaded     * @var boolean     */    public $loaded = false;    /**     * Template was compiled     * @var boolean     */    public $isCompiled = false;    /**     * Source Object     * @var Smarty_Template_Source     */    public $source = null;    /**     * Metadata properties     *     * populated by Smarty_Internal_Template::decodeProperties()     * @var array     */    public $_properties = null;    /**     * create Compiled Object container     *     * @param Smarty_Template_Source $source source object this compiled object belongs to     */    public function __construct(Smarty_Template_Source $source)    {        $this->source = $source;    }}?>
 |