'',
'classname' => 'ObjTemplate.class.php',
'version' => '0.1'
);
var $tag = array(
'begin' => '%',
'delim' => ':',
'end' => '%'
);
var $cmd = array( /* Both sides must be lowercase. */
'if' => 'if',
'else' => 'else',
'endif' => 'endif',
'file' => 'file'
);
var $filename;
var $array;
function ObjTemplate($filename = '')
{
$this->filename = $filename;
return $this->reload();
}
function set_tags($begin_tag = '', $end_tag = '')
{
if (strlen($begin_tag) > 0)
$this->tag['begin'] = $begin_tag;
if (strlen($end_tag) > 0)
$this->tag['end'] = $end_tag;
}
function load($filename)
{
if (file_exists($filename)) { # DEBUG
$this->array = $this->_string_transform(join('', file($filename)), 0);
return true;
}
return false;
}
function reload()
{
if (strlen($this->filename) > 0)
return $this->load($this->filename);
return false;
}
function add_before($string)
{
return array_unshift($this->array, $this->_string_transform($string));
}
function add_after($string)
{
return array_push($this->array, $this->_string_transform($string));
}
function is_key($key)
{
return $this->_is_key(strtolower($key), $this->array);
}
function _is_key($key, $ar)
{
/*
* TODO: optimalization
* try foreach() loop instead for() loop
*/
for ($i = 0; $i < count($ar); $i++) {
if (is_array($ar[$i])) {
if (is_array($ar[$i]['key'])) {
if (true == $this->_is_key($key, $ar[$i]['key']))
return true;
}
elseif (! strcmp($key, $ar[$i]['key'])) {
return true;
}
elseif (! strcmp($this->cmd['if'], $ar[$i]['key'])) {
if (is_array($ar[$i]['conditions'])) {
if (is_array($ar[$i]['conditions']['key'])) {
if (true == $this->_is_key($key, $ar[$i]['conditions']['key']))
return true;
}
else {
if (! strcmp($key, $ar[$i]['conditions']['key']))
return true;
}
}
if (is_array($ar[$i]['true'])) {
if (true == $this->_is_key($key, $ar[$i]['true']))
return true;
}
if (is_array($ar[$i]['false'])) {
if (true == $this->_is_key($key, $ar[$i]['false']))
return true;
}
}
else {
if (true == $this->_is_key($key, $ar[$i]))
return true;
}
}
}
return false;
}
function set($key, $value = "")
{
if (is_array($key)) {
while (list($k, $v) = each($key)) {
if (! empty($k)) {
/* Empty values are allowed. Empty keys are NOT. */
$this->set($k, $v);
}
}
}
else {
$this->_set(strtolower($key), $this->_string_transform($value), $this->array);
}
return;
}
function _set($key, $value, &$ar)
{
for ($i = 0; $i < count($ar); $i++) {
if (is_array($ar[$i])) {
if (isset($ar[$i]['key'])) {
if (is_array($ar[$i]['key']))
$this->_set($key, $value, $ar[$i]['key']);
elseif (! strcmp($this->cmd['if'], $ar[$i]['key'])) {
if (is_array($ar[$i]['conditions'])) {
if (is_array($ar[$i]['conditions']['key'])) {
$this->_set($key, $value, $ar[$i]['conditions']['key']);
}
else {
if (! strcmp($key, $ar[$i]['conditions']['key']))
$ar[$i]['conditions'] = $value;
}
}
if (is_array($ar[$i]['true']))
$this->_set($key, $value, $ar[$i]['true']);
if (is_array($ar[$i]['false']))
$this->_set($key, $value, $ar[$i]['false']);
}
else {
if (! strcmp($key, $ar[$i]['key']))
$ar[$i] = $value;
}
}
else {
$this->_set($key, $value, $ar[$i]);
}
}
}
return;
}
/* TODO: fix conditions in IF */
function get_keys()
{
return array_unique($this->_get_keys($this->array));
}
function _get_keys($ar)
{
$ar_out = array();
for ($i = 0; $i < count($ar); $i++) {
if (is_array($ar[$i])) {
if (! strcmp($this->cmd['if'], $ar[$i]['key'])) {
if (is_array($ar[$i]['conditions'])) {
if (is_array($ar[$i]['conditions']['key'])) {
$ar_out = array_merge($ar_out, $this->_get_keys($ar[$i]['conditions']['key']));
}
else
array_push($ar_out, $ar[$i]['conditions']['key']);
}
if (is_array($ar[$i]['true']))
$ar_out = array_merge($ar_out, $this->_get_keys($ar[$i]['true']));
if (is_array($ar[$i]['false']))
$ar_out = array_merge($ar_out, $this->_get_keys($ar[$i]['false']));
}
elseif (isset($ar[$i]['key'])) {
if (is_array($ar[$i]['key']))
$ar_out = array_merge($ar_out, $this->_get_keys($ar[$i]['key']));
else
array_push($ar_out, $ar[$i]['key']);
}
else {
$ar_out = array_merge($ar_out, $this->_get_keys($ar[$i]));
}
}
}
return $ar_out;
}
function hide()
{
return $this->_get_content($this->array, 'hide');
}
function clean()
{
return $this->_get_content($this->array, 'clean');
}
function html()
{
return $this->_get_content($this->array, 'normal');
}
function _get_content($ar, $mode = "")
{
$string = '';
for ($i = 0; $i < count($ar); $i++) {
if (is_array($ar[$i])) {
if (! strcmp($this->cmd['if'], $ar[$i]['key'])) {
if (is_array($ar[$i]['conditions']))
$evalstr = $this->_final_join($ar[$i]['conditions']['key'], $mode);
else
$evalstr = '"' . $ar[$i]['conditions'] . '"';
if (is_array($evalstr)) {
$string .= $this->tag['begin'] . $this->cmd['if'] . $this->tag['delim'];
$string .= $evalstr['uncompleted'] . $this->tag['end'];
if (is_array($ar[$i]['true']))
$string .= $this->_get_content($ar[$i]['true'], $mode);
else
$string .= $ar[$i]['true'];
if (is_array($ar[$i]['false']))
$string .= $this->tag['begin'].$this->cmd['else'].$this->tag['end']
. $this->_get_content($ar[$i]['false'], $mode);
else
$string .= $this->tag['begin'].$this->cmd['else'].$this->tag['end']
. $ar[$i]['false'];
$string .= $this->tag['begin'].$this->cmd['endif'].$this->tag['end'];
}
else {
$evalcode = "return ($evalstr);";
//print "evalcode = $evalcode
";
if (eval($evalcode)) {
//echo "- returned true
";
if (isset($ar[$i]['true'])) {
if (is_array($ar[$i]['true']))
$string .= $this->_get_content($ar[$i]['true'], $mode);
else
$string .= $ar[$i]['true'];
}
}
else {
//echo "- returned false
";
if (isset($ar[$i]['false'])) {
if (is_array($ar[$i]['false']))
$string .= $this->_get_content($ar[$i]['false'], $mode);
else
$string .= $ar[$i]['false'];
}
}
}
}
elseif (isset($ar[$i]['key'])) {
if (is_array($ar[$i]['key'])) {
$evalcode = "return (".$this->_final_join($ar[$i]['key']).");";
//print "NORMAL evalcode = $evalcode
";
$string .= eval($evalcode);
}
else {
switch ($mode) {
case "clean":
;
break;
case "hide":
$string .= $this->_generate_error("hide: " . $ar[$i]['key']);
break;
default:
$string .= $this->tag['begin'] . $ar[$i]['key'] . $this->tag['end'];
break;
}
}
}
else {
$string .= $this->_get_content($ar[$i], $mode);
}
}
else {
$string .= $ar[$i];
}
}
return $string;
}
function html_array($prefix)
{
$html = $this->html();
$regexp = $this->tag['begin'] . $prefix . $this->tag['delim'] . '([^%\b]+)' .
( isset($this->tag['end']) ? $this->tag['end'] : '\b' ) . '';
preg_match_all("/$regexp/is", $html, $matches);
return array(preg_split("/$regexp/is", $html), $matches[1]);
}
function get_array()
{
return $this->array;
}
function _start_explode($str) {
if (preg_match("/^[\w:]+$/", $str))
return strtolower($str);
$out_ar = array();
$tmpstr = '';
if (preg_match("/^[a-zA-Z]$/", $str[0])) $type = 1;
else $type = 0;
for ($i = 0; $i < strlen($str); $i++) {
if ($type == 1) {
if (preg_match("/^[\w:]$/", $str[$i])) {
$tmpstr .= $str[$i];
}
else {
array_push($out_ar, array('key' => strtolower($tmpstr)));
$tmpstr = $str[$i];
$type = 0;
}
}
else {
if (preg_match("/^[a-zA-Z]$/", $str[$i])) {
array_push($out_ar, $tmpstr);
$tmpstr = $str[$i];
$type = 1;
}
else {
$tmpstr .= $str[$i];
}
}
}
array_push($out_ar, $type ? array('key' => strtolower($tmpstr)) : $tmpstr);
return $out_ar;
}
function _final_join($ar, $mode = "") {
$uncompleted = 0;
if (is_array($ar)) {
// TODO comment
//print "Entering _final_join() with mode [$mode] / array set
";
$ret = '';
foreach ($ar as $i) {
if (is_array($i)) {
switch ($mode) {
case "clean":
;
break;
case "hide":
// $string .= $this->_generate_error("hide: " . $ar[$i]['key']);
break;
default:
$uncompleted = 1;
$ret .= $i['key'];
break;
}
}
else
$ret .= $i;
}
}
else {
switch ($mode) {
case "clean":
$ret = "0";
break;
case "hide":
$ret = "0";
// $string .= $this->_generate_error("hide: " . $ar[$i]['key']);
break;
default:
$uncompleted = 1;
$ret = $ar;
break;
}
}
if ($uncompleted) {
// TODO comment
//print "_final_join(): returning uncompleted ($uncompleted)[$ret]
";
}
return $uncompleted ? array('uncompleted' => $ret) : $ret;
}
function _string_transform($string, $debug = 0)
{
/*
* Spliting string into two arrays by tags. First array ($m_tags) will
* contain only tags without starting prefix and ending sufix.
* The second array ($m_texts) will contain text between tags.
* Elemets goes in this order: $m_texts[0], $m_tags[0], $m_texts[1], ...
*
* Optimalization for this array spliting is strongly required.
*/
$m_texts = $m_tags = array();
if (0) {
/*
* Old method -- remove this.
*/
$regexp = $this->tag['begin'] . '(\w[\w\d_]*(' . $this->tag['delim'] . '[^\b%]+)*)'
. ( isset($this->tag['end']) ? $this->tag['end'] : '\b' );
preg_match_all("/$regexp/is", $string, $m_tags);
$m_tags = $m_tags[1];
$m_texts = preg_split("/$regexp/im", $string);
}
else {
$begin_tag_len = strlen($this->tag['begin']);
$end_tag_len = strlen($this->tag['end']);
$append = 0;
while (1) {
$pos_begin = strpos($string, $this->tag['begin']);
if ($pos_begin === false) {
if ($append) {
$m_texts[count($m_texts) - 1] .= $string;
$append = 0;
}
else {
array_push($m_texts, $string);
}
break;
}
else {
$pos_real_begin = $pos_begin + $begin_tag_len;
$pos_end = strpos($string, $this->tag['end'], $pos_real_begin);
if ($pos_end === false) {
if ($append) {
$m_texts[count($m_texts) - 1] .= $string;
$append = 0;
}
else {
array_push($m_texts, $string);
}
break;
}
else {
$tmpstr = substr($string, $pos_real_begin, $pos_end - $pos_real_begin);
$pos_real_end = $pos_end + $end_tag_len;
if (preg_match('/[\s]/', $tmpstr)) {
if ($debug) echo "MATCHED: [$tmpstr]
";
$pos_begin_2nd = strpos($tmpstr . $this->tag['end'],
$this->tag['begin']);
if ($pos_begin_2nd === false) ;
else $pos_real_end = $pos_real_begin + $pos_begin_2nd;
if ($append) {
$m_texts[count($m_texts) - 1] .=
substr($string, 0, $pos_real_end);
if ($debug) print "-- appending: [".substr($string, 0, $pos_real_end)."]
";
}
else {
array_push($m_texts,
substr($string, 0, $pos_real_end));
if ($debug) print "-- pushing: [".substr($string, 0, $pos_real_end)."]
";
}
$append = 1;
}
else {
if ($debug) echo "NOT MATCHED: [$tmpstr]
";
if ($append) {
$m_texts[count($m_texts) - 1] .= substr($string, 0, $pos_begin);
$append = 0;
}
else {
array_push($m_texts, substr($string, 0, $pos_begin));
}
array_push($m_tags, $tmpstr);
}
$string = substr($string, $pos_real_end);
}
}
}
}
/*
* Debug informations printing.
*/
if ($debug) {
print "_string_transform() DEBUG: m_tags: ";
var_dump($m_tags);
print "
";
print "_string_transform() DEBUG: m_texts: ";
var_dump($m_texts);
print "
";
}
/*
* Main loop.
*/
$ar_out_idx = 0;
for ($i = 0; $i < count($m_texts); $i++) {
/* Text processing. */
if (strlen($m_texts[$i]) > 0) {
if ($ar_out_idx > 0 && ! is_array($ar_out[$ar_out_idx - 1])) {
$ar_out[$ar_out_idx - 1] .= $m_texts[$i];
}
else {
$ar_out[$ar_out_idx] = $m_texts[$i];
$ar_out_idx++;
}
}
/* Tag processing. */
if (strlen($m_tags[$i]) > 0) {
$cmd_parts = explode($this->tag['delim'], $m_tags[$i], 2);
/* FILE tag. */
if (! strcasecmp($this->cmd['file'], $cmd_parts[0])
&& strlen($cmd_parts[1]) > 0) {
$filename_with_path = dirname($this->filename) . '/' . $cmd_parts[1];
if (file_exists($filename_with_path))
$ar_out[$ar_out_idx] =
$this->_string_transform(join('', file($filename_with_path)));
else
$ar_out[$ar_out_idx] =
$this->_generate_error("file not found: $filename_with_path");
}
/* IF tag. */
elseif (! strcasecmp($this->cmd['if'], $cmd_parts[0])) {
$ar_out[$ar_out_idx] = array(
'key' => $this->cmd['if'],
'conditions' => array('key' => $this->_start_explode($cmd_parts[1]))
);
$tmp_str = '';
$level = 0;
for ($j = $i + 1; $j < count($m_texts); $j++) {
$cmd_parts2 = explode($this->tag['delim'], $m_tags[$j], 2);
$tmp_str .= $m_texts[$j];
/* IF subtag. */
if (! strcasecmp($this->cmd['if'], $cmd_parts2[0])) {
$level++;
}
/* ELSE subtag. */
elseif (! $level && ! strcasecmp($this->cmd['else'], $cmd_parts2[0])) {
if (! isset($ar_out[$ar_out_idx]['true'])) {
$ar_out[$ar_out_idx]['true'] =
$this->_string_transform($tmp_str);
$tmp_str = '';
continue;
}
}
/* ENDIF subtag. */
elseif (! strcasecmp($this->cmd['endif'], $cmd_parts2[0])) {
if ($level)
$level--;
else
break;
}
$tmp_str .= $this->tag['begin'] . $m_tags[$j] . $this->tag['end'];
}
if (isset($ar_out[$ar_out_idx]['true']))
$ar_out[$ar_out_idx]['false'] = $this->_string_transform($tmp_str);
else
$ar_out[$ar_out_idx]['true'] = $this->_string_transform($tmp_str);
$i = $j;
}
/* Others tags. */
else {
//$ar_out[$ar_out_idx] = array('key' => strtolower($m_tags[$i]));
$ar_out[$ar_out_idx] = array('key' => $this->_start_explode($m_tags[$i]));
}
$ar_out_idx++;
}
}
if ($debug && $ar_out_idx <= 1)
print "_string_transform() DEBUG: ar_out_idx = $ar_out_idx
";
return $ar_out_idx > 1 ? $ar_out : $ar_out[0];
}
function _generate_error($message = "unknown error")
{
return $this->cstr['begin']
. ' ' . $this->cstr['classname'] . ':'
. ' ' . $message
. ' ' . $this->cstr['end'];
}
}
?>