<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Alan Knowles <alan@akbkhome.com> |
// +----------------------------------------------------------------------+
//
// $Id: Tree.php 334846 2014-09-12 04:50:56Z alan_k $
//
// The Html Tree Component of Flexy
// Designed to be used on it's own
//
//
//
// The concept:
// - it builds a big tokens[] array :
// - filters "Text with {placeholders}" into sprintf formated strings.
// - matches closers to openers eg. token[4]->close = &token[5];
// - it aliases the tokens into token[0] as children as a tree
// - locates the base of the file. (flexy:startchildren.
// returns a nice tree..
class HTML_Template_Flexy_Tree {
/**
* Options for Tree:
* 'ignore' => dont change {xxxX} into placeholders?
* 'filename' => filename of file being parsed. (for error messages.)
* 'ignore_html' => return <html> elements as strings.
* 'ignore_php' => DELETE/DESTROY any php code in the original template.
*/
var $options = array(
'ignore' => false, // was flexyIgnore
'filename' => false,
'ignore_html' => false,
'ignore_php' => true,
);
/**
* Array of all tokens (eg. nodes / text / tags etc. )
* All nodes have ID's
*
* eg.
* <b>some text</b>
* [0] => Token_Tag::
* tagname = '<b>'
* children = array( &tag[1] );
close = &tag[2];
* [1] => Token_Text::'some test'
* [2] => Token_Tag::
* tagname = '</b>';
*
*
* under normal situations, the tree is built into node[0], the remaining nodes are referenced by alias.
* if caching is used (the nodes > 0 will not exist, and everything will just be a child of node 0.
*
*
*
* @var array
* @access public
*/
var $tokens = array();
var $strings = array();
/**
* Run a Tokenizer and Store its results and return the tree.
* It should build a DOM Tree of the HTML
*
* @param string $data data to parse.
* @param array $options see options array.
*
* @access public
* @return base token (really a dummy token, which contains the tree)
* @static
*/
function construct($data,$options=array())
{
// local caching!
$md5 = md5($data);
if (isset($GLOBALS[__CLASS__]['cache'][$md5])) {
return $GLOBALS[__CLASS__]['cache'][$md5];
}
$t = new HTML_Template_Flexy_Tree;
$t->options = $t->options + $options;
require_once 'HTML/Template/Flexy/Token.php';
$t->tokens = array(new HTML_Template_Flexy_Token);
$t->tokens[0]->id =0;
// process
$r = $t->tokenize($data);
if (is_object($r) && is_a($r,'PEAR_Error')) {
return $r;
}
$t->matchClosers();
$t->buildChildren(0);
//new Gtk_VarDump($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][0]);
$GLOBALS[__CLASS__]['cache'][$md5] = $t->returnStart();
return $GLOBALS[__CLASS__]['cache'][$md5];
}
/**
* The core tokenizing part - runs the tokenizer on the data,
* and stores the results in $this->tokens[]
*
* @param string Data to tokenize
*
* @return none | PEAR::Error
* @access public|private
* @see see also methods.....
*/
function tokenize($data) {
require_once 'HTML/Template/Flexy/Tokenizer.php';
$tokenizer = &HTML_Template_Flexy_Tokenizer::construct($data,$this->options);
// initialize state - this trys to make sure that
// you dont do to many elses etc.
//echo "RUNNING TOKENIZER";
// step one just tokenize it.
$i=1;
while ($t = $tokenizer->yylex()) {
if ($t == HTML_TEMPLATE_FLEXY_TOKEN_ERROR) {
return HTML_Template_Flexy::staticRaiseError(
array(
"HTML_Template_Flexy_Tree::Syntax error in File: %s (Line %s)\n".
"Tokenizer Error: %s\n".
"Context:\n\n%s\n\n >>>>>> %s\n",
$this->options['filename'], $tokenizer->yyline ,
$tokenizer->error,
htmlspecialchars(substr($tokenizer->yy_buffer,0,$tokenizer->yy_buffer_end)),
htmlspecialchars(substr($tokenizer->yy_buffer,$tokenizer->yy_buffer_end,100))
)
,HTML_TEMPLATE_FLEXY_ERROR_SYNTAX ,HTML_TEMPLATE_FLEXY_ERROR_DIE);
}
if ($t == HTML_TEMPLATE_FLEXY_TOKEN_NONE) {
continue;
}
if ($t->token == 'Php') {
continue;
}
$i++;
$this->tokens[$i] = $tokenizer->value;
$this->tokens[$i]->id = $i;
//print_r($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]);
}
//echo "BUILT TOKENS";
}
/**
* Match the opening and closing tags eg. </B> is the closer of <B>
*
* aliases the ->close to the tokens[{closeid}] element
*
* @return none
* @access public
*/
function matchClosers()
{
$res = &$this->tokens;
$total = count($this->tokens);
// connect open and close tags.
// this is done by having a stack for each of the tag types..
// then removing it when it finds the closing one
// eg.
// <a href=""><img src=""></a>
// ends up with a stack for <a>'s and a stack for <img>'s
//
//
//
for($i=1;$i<$total;$i++) {
//echo "Checking TAG $i\n";
if (!isset($res[$i]->tag)) {
continue;
}
$tag = strtoupper($res[$i]->tag);
if ($tag{0} != '/') { // it's not a close tag..
if (!isset($stack[$tag])) {
$npos = $stack[$tag]['pos'] = 0;
} else {
$npos = ++$stack[$tag]['pos'];
}
$stack[$tag][$npos] = $i;
continue;
}
//echo "GOT END TAG: {$res[$i]->tag}\n";
$tag = substr($tag,1);
if (!isset($stack[$tag]['pos'])) {
continue; // unmatched
}
$npos = $stack[$tag]['pos'];
if (!isset($stack[$tag][$npos])) {
// stack is empty!!!
continue;
}
// alias closer to opener..
$this->tokens[$stack[$tag][$npos]]->close = &$this->tokens[$i];
$stack[$tag]['pos']--;
// take it off the stack so no one else uses it!!!
unset($stack[$tag][$npos]);
if ($stack[$tag]['pos'] < 0) {
// too many closes - just ignore it..
$stack[$tag]['pos'] = 0;
}
continue;
// new entry on stack..
}
// create a dummy close for the end
$i = $total;
$this->tokens[$i] = new HTML_Template_Flexy_Token;
$this->tokens[$i]->id = $total;
$this->tokens[0]->close = &$this->tokens[$i];
// now is it possible to connect children...
// now we need to GLOBALIZE!! -
}
/**
* Build the child array for each element.
* RECURSIVE FUNCTION!!!!
*
* does not move tokens, just aliases the child nodes into the token array.
*
* @param int id of node to add children to.
*
* @access public
*/
function buildChildren($id)
{
$base = &$this->tokens[$id];
$base->children = array();
$start = $base->id +1;
$end = $base->close->id;
for ($i=$start; $i<$end; $i++) {
//echo "{$base->id}:{$base->tag} ADDING {$i}{$_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->tag}<BR>";
//if ($base->id == 1176) {
// echo "<PRE>";print_r($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]);
// }
$base->children[] = &$this->tokens[$i];
if (isset($this->tokens[$i]->close)) {
// if the close id is greater than my id - ignore it! -
if ($this->tokens[$i]->close->id > $end) {
continue;
}
$this->buildChildren($i);
$i = $this->tokens[$i]->close->id;
}
}
}
/**
* Locates Flexy:startchildren etc. if it is used.
* and returns the base of the tree. (eg. otherwise token[0].
*
* @return HTML_Template_Flexy_Token (base of tree.)
* @access public
*/
function returnStart() {
foreach(array_keys($this->tokens) as $i) {
switch(true) {
case isset($this->tokens[$i]->ucAttributes['FLEXYSTART']):
case isset($this->tokens[$i]->ucAttributes['FLEXY:START']):
$this->tokens[$i]->removeAttribute('FLEXY:START');
$this->tokens[$i]->removeAttribute('FLEXYSTART');
return $this->tokens[$i];
case isset($this->tokens[$i]->ucAttributes['FLEXYSTARTCHILDREN']):
case isset($this->tokens[$i]->ucAttributes['FLEXY:STARTCHILDREN']):
$this->tokens[0]->children = $this->tokens[$i]->children;
return $this->tokens[0];
}
}
return $this->tokens[0];
}
}
Copyright 2K16 - 2K18 Indonesian Hacker Rulez