diff --git a/boards.php b/boards.php
index 86eb69fd..87ba7ddf 100644
--- a/boards.php
+++ b/boards.php
@@ -12,6 +12,7 @@ $boards = listBoards();
$all_tags = array();
$total_posts_hour = 0;
$total_posts = 0;
+$write_maxes = false;
function to_tag($str) {
$str = trim($str);
@@ -20,14 +21,15 @@ function to_tag($str) {
return $str;
}
+if (!file_exists('maxes.txt') || filemtime('maxes.txt') < (time() - (60*60))) {
+ $fp = fopen('maxes.txt', 'w+');
+ $write_maxes = true;
+}
+
foreach ($boards as $i => $board) {
-
- //$query = prepare(sprintf("SELECT (SELECT MAX(id) from ``posts_%s``) AS max, (SELECT MAX(id) FROM ``posts_%s`` WHERE FROM_UNIXTIME(time) < DATE_SUB(NOW(), INTERVAL 1 HOUR)) AS oldmax, (SELECT MAX(id) from ``posts_%s``) AS max_d, (SELECT MAX(id) FROM ``posts_%s`` WHERE FROM_UNIXTIME(time) < DATE_SUB(NOW(), INTERVAL 1 DAY)) AS oldmax_d, (SELECT count(id) FROM ``posts_%s``) AS count;", $board['uri'], $board['uri'], $board['uri'], $board['uri'], $board['uri']));
-
$query = prepare(sprintf("
-SELECT MAX(id) max, (SELECT COUNT(*) FROM ``posts_%s`` WHERE FROM_UNIXTIME(time) > DATE_SUB(NOW(), INTERVAL 1 DAY)) ppd,
+SELECT IFNULL(MAX(id),0) max,
(SELECT COUNT(*) FROM ``posts_%s`` WHERE FROM_UNIXTIME(time) > DATE_SUB(NOW(), INTERVAL 1 HOUR)) pph,
-(SELECT count(id) FROM ``posts_%s``) count,
(SELECT COUNT(DISTINCT ip) FROM ``posts_%s`` WHERE FROM_UNIXTIME(time) > DATE_SUB(NOW(), INTERVAL 3 DAY)) uniq_ip
FROM ``posts_%s``
", $board['uri'], $board['uri'], $board['uri'], $board['uri'], $board['uri']));
@@ -52,17 +54,19 @@ SELECT MAX(id) max, (SELECT COUNT(*) FROM ``posts_%s`` WHERE FROM_UNIXTIME(time)
}
$pph = $r['pph'];
- $ppd = $r['ppd'];
$total_posts_hour += $pph;
$total_posts += $r['max'];
$boards[$i]['pph'] = $pph;
- $boards[$i]['ppd'] = $ppd;
+ $boards[$i]['ppd'] = $pph*24;
$boards[$i]['max'] = $r['max'];
$boards[$i]['uniq_ip'] = $r['uniq_ip'];
$boards[$i]['tags'] = $tags;
+
+ if ($write_maxes) fwrite($fp, $board['uri'] . ':' . $boards[$i]['max'] . "\n");
}
+if ($write_maxes) fclose($fp);
usort($boards,
function ($a, $b) {
@@ -117,14 +121,16 @@ $config['additional_javascript'] = array('js/jquery.min.js', 'js/jquery.tablesor
$body = Element("8chan/boards-tags.html", array("config" => $config, "n_boards" => $n_boards, "t_boards" => $t_boards, "hidden_boards_total" => $hidden_boards_total, "total_posts" => $total_posts, "total_posts_hour" => $total_posts_hour, "boards" => $boards, "last_update" => date('r'), "uptime_p" => shell_exec('uptime -p'), 'tags' => $all_tags, 'top2k' => false));
$html = Element("page.html", array("config" => $config, "body" => $body, "title" => "Boards on ∞chan"));
-array_splice($boards, 2000);
-$boards = array_values($boards);
-$body = Element("8chan/boards-tags.html", array("config" => $config, "n_boards" => $n_boards, "t_boards" => $t_boards, "hidden_boards_total" => $hidden_boards_total, "total_posts" => $total_posts, "total_posts_hour" => $total_posts_hour, "boards" => $boards, "last_update" => date('r'), "uptime_p" => shell_exec('uptime -p'), 'tags' => $all_tags, 'top2k' => true));
+$boards_top2k = $boards;
+array_splice($boards_top2k, 2000);
+$boards_top2k = array_values($boards_top2k);
+$body = Element("8chan/boards-tags.html", array("config" => $config, "n_boards" => $n_boards, "t_boards" => $t_boards, "hidden_boards_total" => $hidden_boards_total, "total_posts" => $total_posts, "total_posts_hour" => $total_posts_hour, "boards" => $boards_top2k, "last_update" => date('r'), "uptime_p" => shell_exec('uptime -p'), 'tags' => $all_tags, 'top2k' => true));
$html_top2k = Element("page.html", array("config" => $config, "body" => $body, "title" => "Boards on ∞chan"));
if ($admin) {
echo $html;
} else {
+ foreach ($boards as $i => &$b) { unset($b['img']); }
file_write("boards.json", json_encode($boards));
file_write("tags.json", json_encode($all_tags));
foreach ($boards as $i => $b) {
diff --git a/faq.php b/faq.php
index b2087c4a..646a9e6c 100644
--- a/faq.php
+++ b/faq.php
@@ -103,14 +103,14 @@ $body = << Top twenty-five boards excluding /meta/, /b/ and /news+/. Top twenty-five boards excluding /meta/, /b/, /operate/, /boards/ and /news+/. No one, so they are de facto property of the administration. No one, so they are de facto managed by the administration. 8chan is centered around user created boards. That's a board with CSS that makes it look like the ban page, not an official page. You've been tricked. 8chan has no official ban check page.strikethrough
How are featured boards chosen?
-Who owns /meta/, /b/ and /news+/?
-Who owns boards like /b/, /news+/ and /operate/?
+Why does https://8ch.net/banned say that I'm banned? I can still use the boards?
There isn't one yet and there will never be an official archive.
Given that archives are inevitable and will be created anyway via archive.today, Google cache, and anyone who installs Asagi, I'm softening my stance on this. Currently, 8archive.moe provides our archive, and I may set up an official one. All archives officially partnered with us will be opt-in by our board owners, not opt-out. Archives who archive boards that have not opted in will be considered pirate archives, and legal action may be taken.
++Assuming the /b/ board, they are as follows:
+There are also endpoints for getting information about 8chan's boards:
+ +Just read the data to get an idea of what is exposed and under what attribute names. It should be self explanatory.
+Endpoints not listed here, like post.php, catalog.json or boards-top20.json are subject to change or removal at any time!
+8chan.co uses cock.li to manage our domain's email. cock.li allows anyone to create an email account @8chan.co.
That said, we have quite a few official 8chan.co email addresses. They are:
diff --git a/inc/functions.php b/inc/functions.php index 3c53043c..382725e2 100755 --- a/inc/functions.php +++ b/inc/functions.php @@ -2410,33 +2410,19 @@ function shell_exec_error($command, $suppress_stdout = false) { */ function diceRoller($post) { global $config; - if(strpos(strtolower($post->email), 'dice%20') === 0) { - $dicestr = str_split(substr($post->email, strlen('dice%20'))); - + if (isset($_POST['dx'], $_POST['dy'], $_POST['dz']) && !empty($_POST['dy'])) { // Get params - $diceX = ''; - $diceY = ''; - $diceZ = ''; - - $curd = 'diceX'; - for($i = 0; $i < count($dicestr); $i ++) { - if(is_numeric($dicestr[$i])) { - $$curd .= $dicestr[$i]; - } else if($dicestr[$i] == 'd') { - $curd = 'diceY'; - } else if($dicestr[$i] == '-' || $dicestr[$i] == '+') { - $curd = 'diceZ'; - $$curd = $dicestr[$i]; - } - } + $diceX = $_POST['dx']; + $diceY = $_POST['dy']; + $diceZ = $_POST['dz']; // Default values for X and Z if($diceX == '') { - $diceX = '1'; + $diceX = 1; } if($diceZ == '') { - $diceZ = '+0'; + $diceZ = 0; } // Intify them @@ -2453,6 +2439,10 @@ function diceRoller($post) { $diceX = 200; } + if (abs($diceZ) > 1000000) { + $diceZ = 0; + } + // Continue only if we have valid values if($diceX > 0 && $diceY > 0) { $dicerolls = array(); @@ -2466,7 +2456,8 @@ function diceRoller($post) { // Prepend the result to the post body $modifier = ($diceZ != 0) ? ((($diceZ < 0) ? ' - ' : ' + ') . abs($diceZ)) : ''; $dicesum = ($diceX > 1) ? ' = ' . $dicesum : ''; - $post->body = 'Rolled ' . implode(', ', $dicerolls) . $modifier . $dicesum . ' |
Rolled ' . implode(', ', $dicerolls) . $modifier . $dicesum . " ($rollstring) |
- * {% if loop.index is divisibleby(3) %} + * {% if loop.index is divisible by(3) %} ** * @author Fabien Potencier
'.parent::dump($profile).''; + } + + protected function formatTemplate(Twig_Profiler_Profile $profile, $prefix) + { + return sprintf('%s└ %s', $prefix, self::$colors['template'], $profile->getTemplate()); + } + + protected function formatNonTemplate(Twig_Profiler_Profile $profile, $prefix) + { + return sprintf('%s└ %s::%s(%s)', $prefix, $profile->getTemplate(), $profile->getType(), isset(self::$colors[$profile->getType()]) ? self::$colors[$profile->getType()] : 'auto', $profile->getName()); + } + + protected function formatTime(Twig_Profiler_Profile $profile, $percent) + { + return sprintf('%.2fms/%.0f%%', $percent > 20 ? self::$colors['big'] : 'auto', $profile->getDuration() * 1000, $percent); + } +} diff --git a/inc/lib/Twig/Profiler/Dumper/Text.php b/inc/lib/Twig/Profiler/Dumper/Text.php new file mode 100644 index 00000000..998e210d --- /dev/null +++ b/inc/lib/Twig/Profiler/Dumper/Text.php @@ -0,0 +1,68 @@ + + */ +class Twig_Profiler_Dumper_Text +{ + private $root; + + public function dump(Twig_Profiler_Profile $profile) + { + return $this->dumpProfile($profile); + } + + protected function formatTemplate(Twig_Profiler_Profile $profile, $prefix) + { + return sprintf('%s└ %s', $prefix, $profile->getTemplate()); + } + + protected function formatNonTemplate(Twig_Profiler_Profile $profile, $prefix) + { + return sprintf('%s└ %s::%s(%s)', $prefix, $profile->getTemplate(), $profile->getType(), $profile->getName()); + } + + protected function formatTime(Twig_Profiler_Profile $profile, $percent) + { + return sprintf('%.2fms/%.0f%%', $profile->getDuration() * 1000, $percent); + } + + private function dumpProfile(Twig_Profiler_Profile $profile, $prefix = '', $sibling = false) + { + if ($profile->isRoot()) { + $this->root = $profile->getDuration(); + $start = $profile->getName(); + } else { + if ($profile->isTemplate()) { + $start = $this->formatTemplate($profile, $prefix); + } else { + $start = $this->formatNonTemplate($profile, $prefix); + } + $prefix .= $sibling ? '│ ' : ' '; + } + + $percent = $this->root ? $profile->getDuration() / $this->root * 100 : 0; + + if ($profile->getDuration() * 1000 < 1) { + $str = $start."\n"; + } else { + $str = sprintf("%s %s\n", $start, $this->formatTime($profile, $percent)); + } + + $nCount = count($profile->getProfiles()); + foreach ($profile as $i => $p) { + $str .= $this->dumpProfile($p, $prefix, $i + 1 !== $nCount); + } + + return $str; + } +} diff --git a/inc/lib/Twig/Profiler/Node/EnterProfile.php b/inc/lib/Twig/Profiler/Node/EnterProfile.php new file mode 100644 index 00000000..11c1114a --- /dev/null +++ b/inc/lib/Twig/Profiler/Node/EnterProfile.php @@ -0,0 +1,40 @@ + + */ +class Twig_Profiler_Node_EnterProfile extends Twig_Node +{ + public function __construct($extensionName, $type, $name, $varName) + { + parent::__construct(array(), array('extension_name' => $extensionName, 'name' => $name, 'type' => $type, 'var_name' => $varName)); + } + + /** + * {@inheritdoc} + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->write(sprintf("\$%s = \$this->env->getExtension(", $this->getAttribute('var_name'))) + ->repr($this->getAttribute('extension_name')) + ->raw(");\n") + ->write(sprintf("\$%s->enter(\$%s = new Twig_Profiler_Profile(\$this->getTemplateName(), ", $this->getAttribute('var_name'), $this->getAttribute('var_name').'_prof')) + ->repr($this->getAttribute('type')) + ->raw(", ") + ->repr($this->getAttribute('name')) + ->raw("));\n\n") + ; + } +} diff --git a/inc/lib/Twig/Profiler/Node/LeaveProfile.php b/inc/lib/Twig/Profiler/Node/LeaveProfile.php new file mode 100644 index 00000000..88074c2f --- /dev/null +++ b/inc/lib/Twig/Profiler/Node/LeaveProfile.php @@ -0,0 +1,34 @@ + + */ +class Twig_Profiler_Node_LeaveProfile extends Twig_Node +{ + public function __construct($varName) + { + parent::__construct(array(), array('var_name' => $varName)); + } + + /** + * {@inheritdoc} + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->write("\n") + ->write(sprintf("\$%s->leave(\$%s);\n\n", $this->getAttribute('var_name'), $this->getAttribute('var_name').'_prof')) + ; + } +} diff --git a/inc/lib/Twig/Profiler/NodeVisitor/Profiler.php b/inc/lib/Twig/Profiler/NodeVisitor/Profiler.php new file mode 100644 index 00000000..58beb0a5 --- /dev/null +++ b/inc/lib/Twig/Profiler/NodeVisitor/Profiler.php @@ -0,0 +1,72 @@ + + */ +class Twig_Profiler_NodeVisitor_Profiler implements Twig_NodeVisitorInterface +{ + private $extensionName; + + public function __construct($extensionName) + { + $this->extensionName = $extensionName; + } + + /** + * {@inheritdoc} + */ + public function enterNode(Twig_NodeInterface $node, Twig_Environment $env) + { + return $node; + } + + /** + * {@inheritdoc} + */ + public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env) + { + if ($node instanceof Twig_Node_Module) { + $varName = $this->getVarName(); + $node->setNode('display_start', new Twig_Node(array(new Twig_Profiler_Node_EnterProfile($this->extensionName, Twig_Profiler_Profile::TEMPLATE, $node->getAttribute('filename'), $varName), $node->getNode('display_start')))); + $node->setNode('display_end', new Twig_Node(array(new Twig_Profiler_Node_LeaveProfile($varName), $node->getNode('display_end')))); + } elseif ($node instanceof Twig_Node_Block) { + $varName = $this->getVarName(); + $node->setNode('body', new Twig_Node_Body(array( + new Twig_Profiler_Node_EnterProfile($this->extensionName, Twig_Profiler_Profile::BLOCK, $node->getAttribute('name'), $varName), + $node->getNode('body'), + new Twig_Profiler_Node_LeaveProfile($varName), + ))); + } elseif ($node instanceof Twig_Node_Macro) { + $varName = $this->getVarName(); + $node->setNode('body', new Twig_Node_Body(array( + new Twig_Profiler_Node_EnterProfile($this->extensionName, Twig_Profiler_Profile::MACRO, $node->getAttribute('name'), $varName), + $node->getNode('body'), + new Twig_Profiler_Node_LeaveProfile($varName), + ))); + } + + return $node; + } + + private function getVarName() + { + return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false)); + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return 0; + } +} diff --git a/inc/lib/Twig/Profiler/Profile.php b/inc/lib/Twig/Profiler/Profile.php new file mode 100644 index 00000000..fe48a4d2 --- /dev/null +++ b/inc/lib/Twig/Profiler/Profile.php @@ -0,0 +1,150 @@ + + */ +class Twig_Profiler_Profile implements IteratorAggregate, Serializable +{ + const ROOT = 'ROOT'; + const BLOCK = 'block'; + const TEMPLATE = 'template'; + const MACRO = 'macro'; + + private $template; + private $name; + private $type; + private $starts = array(); + private $ends = array(); + private $profiles = array(); + + public function __construct($template = 'main', $type = Twig_Profiler_Profile::ROOT, $name = 'main') + { + $this->template = $template; + $this->type = $type; + $this->name = 0 === strpos($name, '__internal_') ? 'INTERNAL' : $name; + $this->enter(); + } + + public function getTemplate() + { + return $this->template; + } + + public function getType() + { + return $this->type; + } + + public function getName() + { + return $this->name; + } + + public function isRoot() + { + return self::ROOT === $this->type; + } + + public function isTemplate() + { + return self::TEMPLATE === $this->type; + } + + public function isBlock() + { + return self::BLOCK === $this->type; + } + + public function isMacro() + { + return self::MACRO === $this->type; + } + + public function getProfiles() + { + return $this->profiles; + } + + public function addProfile(Twig_Profiler_Profile $profile) + { + $this->profiles[] = $profile; + } + + /** + * Returns the duration in microseconds. + * + * @return int + */ + public function getDuration() + { + return isset($this->ends['wt']) && isset($this->starts['wt']) ? $this->ends['wt'] - $this->starts['wt'] : 0; + } + + /** + * Returns the memory usage in bytes. + * + * @return int + */ + public function getMemoryUsage() + { + return isset($this->ends['mu']) && isset($this->starts['mu']) ? $this->ends['mu'] - $this->starts['mu'] : 0; + } + + /** + * Returns the peak memory usage in bytes. + * + * @return int + */ + public function getPeakMemoryUsage() + { + return isset($this->ends['pmu']) && isset($this->starts['pmu']) ? $this->ends['pmu'] - $this->starts['pmu'] : 0; + } + + /** + * Starts the profiling. + */ + public function enter() + { + $this->starts = array( + 'wt' => microtime(true), + 'mu' => memory_get_usage(), + 'pmu' => memory_get_peak_usage(), + ); + } + + /** + * Stops the profiling. + */ + public function leave() + { + $this->ends = array( + 'wt' => microtime(true), + 'mu' => memory_get_usage(), + 'pmu' => memory_get_peak_usage(), + ); + } + + public function getIterator() + { + return new ArrayIterator($this->profiles); + } + + public function serialize() + { + return serialize(array($this->template, $this->name, $this->type, $this->starts, $this->ends, $this->profiles)); + } + + public function unserialize($data) + { + list($this->template, $this->name, $this->type, $this->starts, $this->ends, $this->profiles) = unserialize($data); + } +} diff --git a/inc/lib/Twig/Sandbox/SecurityNotAllowedFilterError.php b/inc/lib/Twig/Sandbox/SecurityNotAllowedFilterError.php new file mode 100644 index 00000000..99faba9d --- /dev/null +++ b/inc/lib/Twig/Sandbox/SecurityNotAllowedFilterError.php @@ -0,0 +1,31 @@ + + */ +class Twig_Sandbox_SecurityNotAllowedFilterError extends Twig_Sandbox_SecurityError +{ + private $filterName; + + public function __construct($message, $functionName, $lineno = -1, $filename = null, Exception $previous = null) + { + parent::__construct($message, $lineno, $filename, $previous); + $this->filterName = $functionName; + } + + public function getFilterName() + { + return $this->filterName; + } +} diff --git a/inc/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.php b/inc/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.php new file mode 100644 index 00000000..05cf488a --- /dev/null +++ b/inc/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.php @@ -0,0 +1,31 @@ + + */ +class Twig_Sandbox_SecurityNotAllowedFunctionError extends Twig_Sandbox_SecurityError +{ + private $functionName; + + public function __construct($message, $functionName, $lineno = -1, $filename = null, Exception $previous = null) + { + parent::__construct($message, $lineno, $filename, $previous); + $this->functionName = $functionName; + } + + public function getFunctionName() + { + return $this->functionName; + } +} diff --git a/inc/lib/Twig/Sandbox/SecurityNotAllowedTagError.php b/inc/lib/Twig/Sandbox/SecurityNotAllowedTagError.php new file mode 100644 index 00000000..b3bb5e8e --- /dev/null +++ b/inc/lib/Twig/Sandbox/SecurityNotAllowedTagError.php @@ -0,0 +1,31 @@ + + */ +class Twig_Sandbox_SecurityNotAllowedTagError extends Twig_Sandbox_SecurityError +{ + private $tagName; + + public function __construct($message, $tagName, $lineno = -1, $filename = null, Exception $previous = null) + { + parent::__construct($message, $lineno, $filename, $previous); + $this->tagName = $tagName; + } + + public function getTagName() + { + return $this->tagName; + } +} diff --git a/inc/lib/Twig/Sandbox/SecurityPolicy.php b/inc/lib/Twig/Sandbox/SecurityPolicy.php index 66ee2332..c4dd03df 100644 --- a/inc/lib/Twig/Sandbox/SecurityPolicy.php +++ b/inc/lib/Twig/Sandbox/SecurityPolicy.php @@ -63,19 +63,19 @@ class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterfac { foreach ($tags as $tag) { if (!in_array($tag, $this->allowedTags)) { - throw new Twig_Sandbox_SecurityError(sprintf('Tag "%s" is not allowed.', $tag)); + throw new Twig_Sandbox_SecurityNotAllowedTagError(sprintf('Tag "%s" is not allowed.', $tag), $tag); } } foreach ($filters as $filter) { if (!in_array($filter, $this->allowedFilters)) { - throw new Twig_Sandbox_SecurityError(sprintf('Filter "%s" is not allowed.', $filter)); + throw new Twig_Sandbox_SecurityNotAllowedFilterError(sprintf('Filter "%s" is not allowed.', $filter), $filter); } } foreach ($functions as $function) { if (!in_array($function, $this->allowedFunctions)) { - throw new Twig_Sandbox_SecurityError(sprintf('Function "%s" is not allowed.', $function)); + throw new Twig_Sandbox_SecurityNotAllowedFunctionError(sprintf('Function "%s" is not allowed.', $function), $function); } } } diff --git a/inc/lib/Twig/Template.php b/inc/lib/Twig/Template.php index a42fab28..caf96428 100644 --- a/inc/lib/Twig/Template.php +++ b/inc/lib/Twig/Template.php @@ -20,11 +20,10 @@ abstract class Twig_Template implements Twig_TemplateInterface protected static $cache = array(); protected $parent; - protected $parents; + protected $parents = array(); protected $env; protected $blocks; protected $traits; - protected $macros; /** * Constructor. @@ -36,7 +35,6 @@ abstract class Twig_Template implements Twig_TemplateInterface $this->env = $env; $this->blocks = array(); $this->traits = array(); - $this->macros = array(); } /** @@ -68,15 +66,25 @@ abstract class Twig_Template implements Twig_TemplateInterface return $this->parent; } - $parent = $this->doGetParent($context); - if (false === $parent) { - return false; - } elseif ($parent instanceof Twig_Template) { - $name = $parent->getTemplateName(); - $this->parents[$name] = $parent; - $parent = $name; - } elseif (!isset($this->parents[$parent])) { - $this->parents[$parent] = $this->env->loadTemplate($parent); + try { + $parent = $this->doGetParent($context); + + if (false === $parent) { + return false; + } + + if ($parent instanceof Twig_Template) { + return $this->parents[$parent->getTemplateName()] = $parent; + } + + if (!isset($this->parents[$parent])) { + $this->parents[$parent] = $this->loadTemplate($parent); + } + } catch (Twig_Error_Loader $e) { + $e->setTemplateFile(null); + $e->guess(); + + throw $e; } return $this->parents[$parent]; @@ -107,9 +115,9 @@ abstract class Twig_Template implements Twig_TemplateInterface $name = (string) $name; if (isset($this->traits[$name])) { - $this->traits[$name][0]->displayBlock($name, $context, $blocks); + $this->traits[$name][0]->displayBlock($name, $context, $blocks, false); } elseif (false !== $parent = $this->getParent($context)) { - $parent->displayBlock($name, $context, $blocks); + $parent->displayBlock($name, $context, $blocks, false); } else { throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block', $name), -1, $this->getTemplateName()); } @@ -121,22 +129,36 @@ abstract class Twig_Template implements Twig_TemplateInterface * This method is for internal use only and should never be called * directly. * - * @param string $name The block name to display - * @param array $context The context - * @param array $blocks The current set of blocks + * @param string $name The block name to display + * @param array $context The context + * @param array $blocks The current set of blocks + * @param bool $useBlocks Whether to use the current set of blocks */ - public function displayBlock($name, array $context, array $blocks = array()) + public function displayBlock($name, array $context, array $blocks = array(), $useBlocks = true) { $name = (string) $name; - if (isset($blocks[$name])) { - $b = $blocks; - unset($b[$name]); - call_user_func($blocks[$name], $context, $b); + if ($useBlocks && isset($blocks[$name])) { + $template = $blocks[$name][0]; + $block = $blocks[$name][1]; } elseif (isset($this->blocks[$name])) { - call_user_func($this->blocks[$name], $context, $blocks); + $template = $this->blocks[$name][0]; + $block = $this->blocks[$name][1]; + } else { + $template = null; + $block = null; + } + + if (null !== $template) { + try { + $template->$block($context, $blocks); + } catch (Twig_Error $e) { + throw $e; + } catch (Exception $e) { + throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getTemplateName(), $e); + } } elseif (false !== $parent = $this->getParent($context)) { - $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks)); + $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false); } } @@ -166,16 +188,17 @@ abstract class Twig_Template implements Twig_TemplateInterface * This method is for internal use only and should never be called * directly. * - * @param string $name The block name to render - * @param array $context The context - * @param array $blocks The current set of blocks + * @param string $name The block name to render + * @param array $context The context + * @param array $blocks The current set of blocks + * @param bool $useBlocks Whether to use the current set of blocks * * @return string The rendered block */ - public function renderBlock($name, array $context, array $blocks = array()) + public function renderBlock($name, array $context, array $blocks = array(), $useBlocks = true) { ob_start(); - $this->displayBlock($name, $context, $blocks); + $this->displayBlock($name, $context, $blocks, $useBlocks); return ob_get_clean(); } @@ -195,7 +218,7 @@ abstract class Twig_Template implements Twig_TemplateInterface * * @param string $name The block name * - * @return Boolean true if the block exists, false otherwise + * @return bool true if the block exists, false otherwise */ public function hasBlock($name) { @@ -217,6 +240,30 @@ abstract class Twig_Template implements Twig_TemplateInterface return array_keys($this->blocks); } + protected function loadTemplate($template, $templateName = null, $line = null, $index = null) + { + try { + if (is_array($template)) { + return $this->env->resolveTemplate($template); + } + + if ($template instanceof Twig_Template) { + return $template; + } + + return $this->env->loadTemplate($template, $index); + } catch (Twig_Error $e) { + $e->setTemplateFile($templateName ? $templateName : $this->getTemplateName()); + if (!$line) { + $e->guess(); + } else { + $e->setTemplateLine($line); + } + + throw $e; + } + } + /** * Returns all blocks. * @@ -237,7 +284,7 @@ abstract class Twig_Template implements Twig_TemplateInterface */ public function display(array $context, array $blocks = array()) { - $this->displayWithErrorHandling($this->env->mergeGlobals($context), $blocks); + $this->displayWithErrorHandling($this->env->mergeGlobals($context), array_merge($this->blocks, $blocks)); } /** @@ -278,7 +325,7 @@ abstract class Twig_Template implements Twig_TemplateInterface throw $e; } catch (Exception $e) { - throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, null, $e); + throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getTemplateName(), $e); } } @@ -301,9 +348,9 @@ abstract class Twig_Template implements Twig_TemplateInterface * access for versions of PHP before 5.4. This is not a way to override * the way to get a variable value. * - * @param array $context The context - * @param string $item The variable to return from the context - * @param Boolean $ignoreStrictCheck Whether to ignore the strict variable check or not + * @param array $context The context + * @param string $item The variable to return from the context + * @param bool $ignoreStrictCheck Whether to ignore the strict variable check or not * * @return The content of the context variable * @@ -313,7 +360,7 @@ abstract class Twig_Template implements Twig_TemplateInterface { if (!array_key_exists($item, $context)) { if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return null; + return; } throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist', $item), -1, $this->getTemplateName()); @@ -325,12 +372,12 @@ abstract class Twig_Template implements Twig_TemplateInterface /** * Returns the attribute value for a given array/object. * - * @param mixed $object The object or array from where to get the item - * @param mixed $item The item to get from the array or object - * @param array $arguments An array of arguments to pass if the item is an object method - * @param string $type The type of attribute (@see Twig_Template constants) - * @param Boolean $isDefinedTest Whether this is only a defined check - * @param Boolean $ignoreStrictCheck Whether to ignore the strict attribute check or not + * @param mixed $object The object or array from where to get the item + * @param mixed $item The item to get from the array or object + * @param array $arguments An array of arguments to pass if the item is an object method + * @param string $type The type of attribute (@see Twig_Template constants) + * @param bool $isDefinedTest Whether this is only a defined check + * @param bool $ignoreStrictCheck Whether to ignore the strict attribute check or not * * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true * @@ -358,18 +405,26 @@ abstract class Twig_Template implements Twig_TemplateInterface } if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return null; + return; } - if (is_object($object)) { - throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $arrayItem, get_class($object)), -1, $this->getTemplateName()); + if ($object instanceof ArrayAccess) { + $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist', $arrayItem, get_class($object)); + } elseif (is_object($object)) { + $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface', $item, get_class($object)); } elseif (is_array($object)) { - throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object))), -1, $this->getTemplateName()); + if (empty($object)) { + $message = sprintf('Key "%s" does not exist as the array is empty', $arrayItem); + } else { + $message = sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object))); + } } elseif (Twig_Template::ARRAY_CALL === $type) { - throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName()); + $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object); } else { - throw new Twig_Error_Runtime(sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName()); + $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object); } + + throw new Twig_Error_Runtime($message, -1, $this->getTemplateName()); } } @@ -379,14 +434,12 @@ abstract class Twig_Template implements Twig_TemplateInterface } if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return null; + return; } throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName()); } - $class = get_class($object); - // object property if (Twig_Template::METHOD_CALL !== $type) { if (isset($object->$item) || array_key_exists((string) $item, $object)) { @@ -402,11 +455,14 @@ abstract class Twig_Template implements Twig_TemplateInterface } } + $class = get_class($object); + // object method if (!isset(self::$cache[$class]['methods'])) { self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object))); } + $call = false; $lcItem = strtolower($item); if (isset(self::$cache[$class]['methods'][$lcItem])) { $method = (string) $item; @@ -416,13 +472,14 @@ abstract class Twig_Template implements Twig_TemplateInterface $method = 'is'.$item; } elseif (isset(self::$cache[$class]['methods']['__call'])) { $method = (string) $item; + $call = true; } else { if ($isDefinedTest) { return false; } if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return null; + return; } throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName()); @@ -436,7 +493,16 @@ abstract class Twig_Template implements Twig_TemplateInterface $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method); } - $ret = call_user_func_array(array($object, $method), $arguments); + // Some objects throw exceptions when they have __call, and the method we try + // to call is not supported. If ignoreStrictCheck is true, we should return null. + try { + $ret = call_user_func_array(array($object, $method), $arguments); + } catch (BadMethodCallException $e) { + if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) { + return; + } + throw $e; + } // useful when calling a template method from a template // this is not supported but unfortunately heavily used in the Symfony profiler @@ -446,72 +512,4 @@ abstract class Twig_Template implements Twig_TemplateInterface return $ret; } - - /** - * Calls macro in a template. - * - * @param Twig_Template $template The template - * @param string $macro The name of macro - * @param array $arguments The arguments of macro - * @param array $namedNames An array of names of arguments as keys - * @param integer $namedCount The count of named arguments - * @param integer $positionalCount The count of positional arguments - * - * @return string The content of a macro - * - * @throws Twig_Error_Runtime if the macro is not defined - * @throws Twig_Error_Runtime if the argument is defined twice - * @throws Twig_Error_Runtime if the argument is unknown - */ - protected function callMacro(Twig_Template $template, $macro, array $arguments, array $namedNames = array(), $namedCount = 0, $positionalCount = -1) - { - if (!isset($template->macros[$macro]['reflection'])) { - if (!isset($template->macros[$macro])) { - throw new Twig_Error_Runtime(sprintf('Macro "%s" is not defined in the template "%s".', $macro, $template->getTemplateName())); - } - - $template->macros[$macro]['reflection'] = new ReflectionMethod($template, $template->macros[$macro]['method']); - } - - if ($namedCount < 1) { - return $template->macros[$macro]['reflection']->invokeArgs($template, $arguments); - } - - $i = 0; - $args = array(); - foreach ($template->macros[$macro]['arguments'] as $name => $value) { - if (isset($namedNames[$name])) { - if ($i < $positionalCount) { - throw new Twig_Error_Runtime(sprintf('Argument "%s" is defined twice for macro "%s" defined in the template "%s".', $name, $macro, $template->getTemplateName())); - } - - $args[] = $arguments[$name]; - if (--$namedCount < 1) { - break; - } - } elseif ($i < $positionalCount) { - $args[] = $arguments[$i]; - } else { - $args[] = $value; - } - - $i++; - } - - if ($namedCount > 0) { - $parameters = array_keys(array_diff_key($namedNames, $template->macros[$macro]['arguments'])); - - throw new Twig_Error_Runtime(sprintf('Unknown argument%s "%s" for macro "%s" defined in the template "%s".', count($parameters) > 1 ? 's' : '' , implode('", "', $parameters), $macro, $template->getTemplateName())); - } - - return $template->macros[$macro]['reflection']->invokeArgs($template, $args); - } - - /** - * This method is only useful when testing Twig. Do not use it. - */ - public static function clearCache() - { - self::$cache = array(); - } } diff --git a/inc/lib/Twig/TemplateInterface.php b/inc/lib/Twig/TemplateInterface.php index 879f503e..d178832e 100644 --- a/inc/lib/Twig/TemplateInterface.php +++ b/inc/lib/Twig/TemplateInterface.php @@ -13,7 +13,8 @@ * Interface implemented by all compiled templates. * * @author Fabien Potencier
"+v+"");r.document.write("
"+v+" |