Skip to content

Commit

Permalink
! BC Break: {include} and {extends} now support the include path prop…
Browse files Browse the repository at this point in the history
…erly,

  which means that if you include "foo/bar.html" from _any_ template and you
  have an include path set on your template object, it will look in all those
  paths for foo/bar.html. If you use relative paths, for example
  if you include "../foo/bar.html" AND have an include path set, you will now
  have a problem, because you can't mix both approaches, otherwise you should
  be fine, so to fix this you should convert your relative includes/extends
  
* Dwoo->get() is now stricter as to what it accepts as a "template", only
  Dwoo_ITemplate objects or valid filenames are accepted

* Foreach and other similar plugins that support "else" now only count()
  their input before processing when an else block follows

git-svn-id: svn://dwoo.org/dwoo/trunk@163 0598d79b-80c4-4d41-97ba-ac86fbbd088b
  • Loading branch information
Seldaek authored and Seldaek committed Aug 31, 2008
1 parent 2b4ad8a commit 848d2a8
Show file tree
Hide file tree
Showing 26 changed files with 363 additions and 292 deletions.
13 changes: 12 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
[2008-0-] 0.9.4 / 1.0.0 ?
[2008-09-] 0.9.4
! BC Break: {include} and {extends} now support the include path properly,
which means that if you include "foo/bar.html" from _any_ template and you
have an include path set on your template object, it will look in all those
paths for foo/bar.html. If you use relative paths, for example
if you include "../foo/bar.html" AND have an include path set, you will now
have a problem, because you can't mix both approaches, otherwise you should
be fine, so to fix this you should convert your relative includes/extends
+ API: Added Dwoo_Compilation_Exception methods getCompiler() and
getTemplate() so you can catch the exception and use those to build a nicer
error view with all the details you want
Expand All @@ -8,6 +15,10 @@
however since it is really bad practice I won't spend time fixing edge
cases, which are $ and '/" characters inside the string. Those will break
it and that's it.. if you really care feel free to send a patch
* Dwoo->get() is now stricter as to what it accepts as a "template", only
Dwoo_ITemplate objects or valid filenames are accepted
* Foreach and other similar plugins that support "else" now only count()
their input before processing when an else block follows
* Fixed compiler bug that created a parse error when you had comments in an
extended template
* Fixed extends bug when extending files in other directories using relative
Expand Down
22 changes: 10 additions & 12 deletions lib/Dwoo.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

include 'Dwoo/IPluginProxy.php';
include 'Dwoo/ILoader.php';
include 'Dwoo/IElseable.php';
include 'Dwoo/Loader.php';
include 'Dwoo/Exception.php';
include 'Dwoo/Security/Policy.php';
Expand Down Expand Up @@ -352,15 +353,8 @@ public function get($_tpl, $data = array(), $_compiler = null, $_output = false)
// auto-create template if required
if ($_tpl instanceof Dwoo_ITemplate) {
// valid, skip
} elseif (is_string($_tpl)) {
if (file_exists($_tpl)) {
$_tpl = new Dwoo_Template_File($_tpl);
} elseif (strstr($_tpl, ':')) {
$_bits = explode(':', $_tpl, 2);
$_tpl = $this->templateFactory($_bits[0], $_bits[1]);
} else {
$_tpl = new Dwoo_Template_String($_tpl);
}
} elseif (is_string($_tpl) && file_exists($_tpl)) {
$_tpl = new Dwoo_Template_File($_tpl);
} else {
throw new Dwoo_Exception('Dwoo->get/Dwoo->output\'s first argument must be a Dwoo_ITemplate (i.e. Dwoo_Template_File) or a valid path to a template file', E_USER_NOTICE);
}
Expand Down Expand Up @@ -889,10 +883,11 @@ public function clearCache($olderThan=-1)
* @param string $compileId the unique compiler identifier
* @return Dwoo_ITemplate
*/
public function templateFactory($resourceName, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null)
public function templateFactory($resourceName, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null)
{
if (isset($this->resources[$resourceName])) {
return call_user_func(array($this->resources[$resourceName]['class'], 'templateFactory'), $this, $resourceId, $cacheTime, $cacheId, $compileId);
// TODO could be changed to $this->resources[$resourceName]['class']::templateFactory(..) in 5.3 maybe
return call_user_func(array($this->resources[$resourceName]['class'], 'templateFactory'), $this, $resourceId, $cacheTime, $cacheId, $compileId, $parentTemplate);
} else {
throw new Dwoo_Exception('Unknown resource type : '.$resourceName);
}
Expand Down Expand Up @@ -944,7 +939,10 @@ public function isArray($value, $checkIsEmpty=false, $allowNonCountable=false)
*/
public function triggerError($message, $level=E_USER_NOTICE)
{
trigger_error('Dwoo error (in '.$this->template->getResourceIdentifier().') : '.$message, $level);
if (!($tplIdentifier = $this->template->getResourceIdentifier())) {
$tplIdentifier = $this->template->getResourceName();
}
trigger_error('Dwoo error (in '.$tplIdentifier.') : '.$message, $level);
}

/*
Expand Down
38 changes: 28 additions & 10 deletions lib/Dwoo/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -525,13 +525,16 @@ public function setTemplateSource($newSource, $fromPointer = false)
/**
* returns the template that is being compiled
*
* @param bool $fromPointer if set to true, only the source from the current pointer position is returned
* @param mixed $fromPointer if set to true, only the source from the current pointer
* position is returned, if a number is given it overrides the current pointer
* @return string the template or partial template
*/
public function getTemplateSource($fromPointer = false)
{
if ($fromPointer) {
if ($fromPointer === true) {
return substr($this->templateSource, $this->pointer);
} elseif (is_numeric($fromPointer)) {
return substr($this->templateSource, $fromPointer);
} else {
return $this->templateSource;
}
Expand Down Expand Up @@ -872,7 +875,7 @@ public function addBlock($type, array $params, $paramtype)

$params = $this->mapParams($params, array($class, 'init'), $paramtype);

$this->stack[] = array('type' => $type, 'params' => $params, 'custom' => false, 'buffer' => null);
$this->stack[] = array('type' => $type, 'params' => $params, 'custom' => false, 'class' => $class, 'buffer' => null);
$this->curBlock =& $this->stack[count($this->stack)-1];
return call_user_func(array($class,'preProcessing'), $this, $params, '', '', $type);
}
Expand All @@ -896,7 +899,7 @@ public function addCustomBlock($type, array $params, $paramtype)

$params = $this->mapParams($params, array($class, 'init'), $paramtype);

$this->stack[] = array('type' => $type, 'params' => $params, 'custom' => true, 'class'=>$class, 'buffer' => null);
$this->stack[] = array('type' => $type, 'params' => $params, 'custom' => true, 'class' => $class, 'buffer' => null);
$this->curBlock =& $this->stack[count($this->stack)-1];
return call_user_func(array($class,'preProcessing'), $this, $params, '', '', $type);
}
Expand All @@ -915,7 +918,7 @@ public function injectBlock($type, array $params)
if (class_exists($class, false) === false) {
$this->dwoo->getLoader()->loadPlugin($type);
}
$this->stack[] = array('type' => $type, 'params' => $params, 'custom' => false, 'buffer' => null);
$this->stack[] = array('type' => $type, 'params' => $params, 'custom' => false, 'class' => $class, 'buffer' => null);
$this->curBlock =& $this->stack[count($this->stack)-1];
}

Expand Down Expand Up @@ -981,7 +984,7 @@ public function &findBlock($type, $closeAlong = false)
if ($b['type']===$type) {
return $this->stack[key($this->stack)];
}
$this->removeTopBlock();
$this->push($this->removeTopBlock(), 0);
}
} else {
end($this->stack);
Expand Down Expand Up @@ -1037,8 +1040,11 @@ public function removeTopBlock()
*/
public function getCompiledParams(array $params)
{
foreach ($params as &$p)
$p = $p[0];
foreach ($params as $k=>$p) {
if (is_array($p)) {
$params[$k] = $p[0];
}
}
return $params;
}

Expand All @@ -1050,8 +1056,11 @@ public function getCompiledParams(array $params)
*/
public function getRealParams(array $params)
{
foreach ($params as &$p)
$p = $p[1];
foreach ($params as $k=>$p) {
if (is_array($p)) {
$params[$k] = $p[1];
}
}
return $params;
}

Expand Down Expand Up @@ -1124,10 +1133,19 @@ protected function parse($in, $from, $to, $parsingParams = false, $curBlock='',
return $this->parse($in, $from+1, $to, false, 'root', $pointer);
} elseif ($curBlock === 'root' && preg_match('#^/([a-z][a-z0-9_]*)?#i', $substr, $match)) {
// close block
if (!empty($match[1]) && $match[1] == 'else') {
throw new Dwoo_Compilation_Exception($this, 'Else blocks must not be closed explicitly, they are automatically closed when their parent block is closed');
}
if (!empty($match[1]) && $match[1] == 'elseif') {
throw new Dwoo_Compilation_Exception($this, 'Elseif blocks must not be closed explicitly, they are automatically closed when their parent block is closed or a new else/elseif block is declared after them');
}
if ($pointer !== null) {
$pointer += strlen($match[0]);
}
if (empty($match[1])) {
if ($this->curBlock['type'] == 'else' || $this->curBlock['type'] == 'elseif') {
$pointer -= strlen($match[0]);
}
if ($this->debug) echo 'TOP BLOCK CLOSED<br />';
return $this->removeTopBlock();
} else {
Expand Down
29 changes: 29 additions & 0 deletions lib/Dwoo/IElseable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

/**
* interface that represents a block plugin that supports the else functionality
*
* the else block will enter an "hasElse" parameter inside the parameters array
* of the closest parent implementing this interface, the hasElse parameter contains
* the else output that should be appended to the block's content (see foreach or other
* block for examples)
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the use of this software.
*
* This file is released under the LGPL
* "GNU Lesser General Public License"
* More information can be found here:
* {@link http://www.gnu.org/copyleft/lesser.html}
*
* @author Jordi Boggiano <j.boggiano@seld.be>
* @copyright Copyright (c) 2008, Jordi Boggiano
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
* @link http://dwoo.org/
* @version 0.9.1
* @date 2008-05-30
* @package Dwoo
*/
interface Dwoo_IElseable
{
}
10 changes: 8 additions & 2 deletions lib/Dwoo/ITemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,13 @@ public function getUid();
public function getCompiler();

/**
* returns a new template object from the given include name, null if no include is
* returns a new template object from the given resource identifier, null if no include is
* possible (resource not found), or false if include is not permitted by this resource type
*
* this method should also check if $dwoo->getSecurityPolicy() is null or not and do the
* necessary permission checks if required, if the security policy prevents the template
* generation it should throw a new Dwoo_Security_Exception with a relevant message
*
* @param mixed $resourceId the resource identifier
* @param int $cacheTime duration of the cache validity for this template,
* if null it defaults to the Dwoo instance that will
Expand All @@ -134,7 +138,9 @@ public function getCompiler();
* to the current url
* @param string $compileId the unique compiled identifier, which is used to distinguish this
* template from others, if null it defaults to the filename+bits of the path
* @param Dwoo_ITemplate $parentTemplate the template that is requesting a new template object (through
* an include, extends or any other plugin)
* @return Dwoo_ITemplate|null|false
*/
public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null);
public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null);
}
3 changes: 3 additions & 0 deletions lib/Dwoo/Security/Policy.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ public function getAllowedPhpFunctions()
/**
* adds a directory to the safelist for includes and other file-access plugins
*
* note that all the includePath directories you provide to the Dwoo_Template_File class
* are automatically marked as safe
*
* @param mixed $path a path name or an array of paths
*/
public function allowDirectory($path)
Expand Down
52 changes: 40 additions & 12 deletions lib/Dwoo/Template/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -219,33 +219,61 @@ public function getUid()
* to the current url
* @param string $compileId the unique compiled identifier, which is used to distinguish this
* template from others, if null it defaults to the filename+bits of the path
* @param Dwoo_ITemplate $parentTemplate the template that is requesting a new template object (through
* an include, extends or any other plugin)
* @return Dwoo_Template_File|null
*/
public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null)
public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null)
{
$resourceId = str_replace(array("\t", "\n", "\r", "\f", "\v"), array('\\t', '\\n', '\\r', '\\f', '\\v'), $resourceId);
if (DIRECTORY_SEPARATOR === '\\') {
$resourceId = str_replace(array("\t", "\n", "\r", "\f", "\v"), array('\\t', '\\n', '\\r', '\\f', '\\v'), $resourceId);
}
$resourceId = strtr($resourceId, '\\', '/');

$includePath = null;

if (file_exists($resourceId) === false) {
$tpl = $dwoo->getTemplate();
if ($tpl instanceof Dwoo_Template_File) {
$resourceId = dirname($tpl->getResourceIdentifier()).DIRECTORY_SEPARATOR.$resourceId;
if (file_exists($resourceId) === false) {
return null;
if ($parentTemplate === null) {
$parentTemplate = $dwoo->getTemplate();
}
if ($parentTemplate instanceof Dwoo_Template_File) {
if ($includePath = $parentTemplate->getIncludePath()) {
if (strstr($resourceId, '../')) {
throw new Dwoo_Exception('When using an include path you can not reference a template into a parent directory (using ../)');
}
} else {
$resourceId = dirname($parentTemplate->getResourceIdentifier()).DIRECTORY_SEPARATOR.$resourceId;
if (file_exists($resourceId) === false) {
return null;
}
}
} else {
return null;
}
}

// prevent template recursion if security is in effect
if ($policy = $dwoo->getSecurityPolicy()) {
$tpl = $dwoo->getTemplate();
if ($tpl instanceof Dwoo_Template_File && $resourceId === $tpl->getResourceIdentifier()) {
return $dwoo->triggerError('You can not include a template into itself', E_USER_WARNING);
while (true) {
if (preg_match('{^([a-z]+?)://}i', $resourceId)) {
throw new Dwoo_Security_Exception('The security policy prevents you to read files from external sources : <em>'.$resourceId.'</em>.');
}

if ($includePath) {
break;
}

$resourceId = realpath($resourceId);
$dirs = $policy->getAllowedDirectories();
foreach ($dirs as $dir=>$dummy) {
if (strpos($resourceId, $dir) === 0) {
break 2;
}
}
throw new Dwoo_Security_Exception('The security policy prevents you to read <em>'.$resourceId.'</em>');
}
}

return new Dwoo_Template_File($resourceId, $cacheTime, $cacheId, $compileId);
return new Dwoo_Template_File($resourceId, $cacheTime, $cacheId, $compileId, $includePath);
}

/**
Expand Down
11 changes: 7 additions & 4 deletions lib/Dwoo/Template/String.php
Original file line number Diff line number Diff line change
Expand Up @@ -346,8 +346,9 @@ public function getCompiledTemplate(Dwoo $dwoo, Dwoo_ICompiler $compiler = null)
}

/**
* returns false as this template type does not support inclusions
* returns a new template string object with the resource id being the template source code
*
* @param Dwoo $dwoo the dwoo instance requiring it
* @param mixed $resourceId the filename (relative to this template's dir) of the template to include
* @param int $cacheTime duration of the cache validity for this template,
* if null it defaults to the Dwoo instance that will
Expand All @@ -357,11 +358,13 @@ public function getCompiledTemplate(Dwoo $dwoo, Dwoo_ICompiler $compiler = null)
* to the current url
* @param string $compileId the unique compiled identifier, which is used to distinguish this
* template from others, if null it defaults to the filename+bits of the path
* @return false
* @param Dwoo_ITemplate $parentTemplate the template that is requesting a new template object (through
* an include, extends or any other plugin)
* @return Dwoo_Template_String
*/
public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null)
public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null)
{
return false;
return new self($resourceId, $cacheTime, $cacheId, $compileId);
}

/**
Expand Down
Loading

0 comments on commit 848d2a8

Please sign in to comment.