conecta($con, $local, $user, $pass, $base); } function bd_executa($sql, $con, $per_page=NULL, $index=NULL, $relacional=false) { return $GLOBALS['BD']->executa($sql, $con, $per_page, $index, $relacional); } function bd_ray($chave, $valor, $tabela, $con, $sql_param='') { return $GLOBALS['BD']->ray($chave, $valor, $tabela, $con, $sql_param); } function bd_random($tabela, $con, $id='id') { return $GLOBALS['BD']->random($tabela, $con, $id); } function bd_searchqry($keywords, $fields) { return $GLOBALS['BD']->searchqry($keywords, $fields); } function bd_nextindex($tabela, $con) { return $GLOBALS['BD']->nextindex($tabela, $con); } function bd_ray_rel($chave, $valor, $rel, $tabela, $con, $ini_rel=0, $spacer=' ', $sql_param='') { return $GLOBALS['BD']->ray_rel($chave, $valor, $rel, $tabela, $con, $ini_rel, $spacer, $sql_param); } function bd_pause_backup() { return $GLOBALS['BD']->backup_enabled = false; } function bd_continue_backup() { return $GLOBALS['BD']->backup_enabled = true; } ##### Classe ############################################################### class BD_MYSQL { private $con; private $cons; function __construct () { $this->backup_enabled = true; // habilita e desabilita os backups $this->con = (object) array(); // handler das conexões $this->cons = (object) array(); // handler das prepriedades das conexões } #\_ Função para proteção de chamada a bibliotecas externas - LOG function __log($str) // 09 10 2008 { if(function_exists('log_do')) log_do($str); } #\_ Função para proteção de chamada a bibliotecas externas - REPORT function __report($str) // 09 10 2008 { if(function_exists('report')) report($str); else { print($str); exit; } } #\_ Função para realizar múltiplas conexões no banco de dados function conecta($con, $local, $user, $pass, $bd) { if(isset($this->con->$con)) // conexão já existente { $this->__report("BD: A conexão $con já existe!!!".NL. 'Não é possível sobreescrever uma conexão já existente.'); } else { $this->__log('BD: Conecta -> Con -> '.$con. ', Local -> '.$local. ', User -> '.$user. ', Pass -> '.$pass. ', Base -> '.$bd); $new_link = false; // new link protection foreach($this->cons as $c) // new link check 13/06/2008 { if($c->local == $local and $c->user == $user and $c->pass == $pass and $c->bd != $bd) $new_link = true; } $this->con->$con = 'off'; $this->cons->{$con} = (object) array('local' => $local, 'user' => $user, 'pass' => $pass, 'bd' => $bd, 'new_link' => $new_link, 'status' => 'off'); } return true; } #\_ Função para preparar conexão com o mysql private function prepare_con($con) { $obj = &$this->cons->{$con}; if($obj->status == 'off') { if(!($this->con->$con = mysql_connect($obj->local, $obj->user, $obj->pass, $obj->new_link))) { $this->__report('Não foi possível conectar.'.NL. 'O Erro apontado foi o seguinte: '.NL. ' '.mysql_error()); } else { if(!(mysql_select_db($obj->bd , $this->con->$con))) { $this->__report("Não foi possível selecionar o Banco de Dados $bd.".NL. 'O Erro apontado foi o seguinte: '.NL. ' '.mysql_error()); } $obj->status = 'on'; @register_shutdown_function('mysql_close', $this->con->$con); } } } #\_ Função para executar um comando SQL, com ou sem paginação function executa($sql, $con, $pag=NULL, $ini=NULL, $relacional=false) { $this->__log('BD: Executa -> Sql -> '.$sql.', Con -> '.$con); // log $pag = ($pag==NULL)?'':$pag; $ini = ($ini==NULL)?0:$ini; $this->prepare_con($con); if(!isset($this->con->$con)) // verificação de existência $this->__report("BD: $con não é uma conexão válida com o Banco de Dados."); else { $ret = (object) array(); // buffer do retorno $ret->res = (object) array(); // buffer do retorno de resposta $ret->nada = false; // buffer do retorno de resposta if($pag == '') # sem paginação { // Backup de dados alterados e/ou removidos - 2008 10 08 $this->do_backup($sql, $con); $qry = mysql_query($sql, $this->con->$con); if(!$qry) { $this->__report('Não foi possível executar o seguinte pedido no Banco de Dados: '.NL. ' '.$sql.NL. 'O Erro apontado foi o seguinte: '.NL. ' '.mysql_error()); } if((preg_match("/INSERT/i", $sql) or preg_match("/UPDATE/i", $sql) or preg_match("/DELETE/i", $sql)) and !preg_match("/SELECT/i", $sql)) return mysql_insert_id($this->con->$con); $lin = mysql_num_rows($qry); $ret->lin = $lin; if($lin == 0) $ret->nada = true; } else # com paginação { /* RESTORE 011 */ $sql = $sql.' LIMIT ' . $ini . " , " . $pag; $sql = $this->_treatSql($sql); if(!($qry = mysql_query($sql, $this->con->$con))) { $this->__report('Não foi possível executar o seguinte pedido no Banco de Dados: '.NL. ' '.$sql.NL. 'O Erro apontado foi o seguinte: '.NL. ' '.mysql_error()); } $ret->sql = $sql; $lin = $this->_lins($sql, $con); // linhas da query $totallin = $lin; $ret->totallin = $lin; $ret->lin = $lin; $ret->voltar = NULL; $ret->avancar = NULL; if($lin > 0) { if(($ini + $pag) < $lin) $ret->avancar = $ini + $pag; if(($ini - $pag) >= 0) $ret->voltar = $ini - $pag; $pagT = intval($lin / $pag); if(($lin - $pagT) > 0) $pagT++; for($c = 1; $c <= $pagT; $c++) { $cont = $pag * ($c - 1); if($cont < $lin) { if($cont == 0) $cont = 'zero'; if($cont != $ini) $pagTR[$c] = $cont; else $pagTR[$c] = ''; } } $ret->pags = $pagTR; } else $ret->nada = true; } if(isset($qry)) { $i = 0; while($res = mysql_fetch_object($qry)) { if($relacional) // 2008-10-06 $o = $res->key; else $o = "rid".$i++; $ret->res->$o = $res; } } } return $ret; } /* RESTORE 012 */ #\_ Função que retorna as linhas de determinada tabela COM CONDIÇÕES function _lins($sql, $con) { $q = mysql_query("SELECT FOUND_ROWS() as i", $this->con->$con); $r = mysql_fetch_object($q); return $r->i; } #\_ Função que retorna a sql consertada para retornar o número de linas posteriormente function _treatSql($sql) { $first = strpos($sql, 'SELECT')+strlen('SELECT'); $sql = substr($sql, 0, $first).' SQL_CALC_FOUND_ROWS'.substr($sql, $first); return $sql; } #\_ Função q retorna um array do bd function ray($chave, $valor, $tabela, $con, $param = '') { $res = bd_executa("SELECT $chave, $valor FROM $tabela $param", $con); if($res->nada) return array(); foreach($res->res as $key) { $chav = array(); $valo = array(); $keys = explode(',', $chave); $values = explode(',', $valor); foreach($keys as $k) $chav[] = $key->$k; foreach($values as $k) $valo[] = $key->$k; $r[implode(' - ',$chav)] = implode(' - ',$valo); } return $r; } #\_ Função q retorna um array do bd relacionado e formato function ray_rel($chave, $valor, $rel, $tabela, $con, $ini=0, $spacer=' ', $param = '') { $res = bd_executa("SELECT $chave, $valor FROM $tabela WHERE $rel = '$ini' $param", $con); if($res->nada) return array(); foreach($res->res as $key) { $chave_str = array(); $valor_str = array(); $keys = explode(',', $chave); $values = explode(',', $valor); foreach($keys as $k) $chave_str[] = $key->$k; foreach($values as $k) $valor_str[] = $key->$k; $main_key = array_shift($keys); $r[implode(' - ',$chave_str)] = $spacer.''.implode(' - ',$valor_str); $childs = $this->ray_rel($chave, $valor, $rel, $tabela, $con, $key->$main_key, $spacer.$spacer, $param); $r = array_merge_safe($r, $childs); } return $r; } #\_ Função q retorna um id randômico function random($tabela, $con, $chave='id') { $res = bd_executa('SELECT ( RAND() * (SELECT MAX('.$chave.') FROM '.$tabela.') ) AS id', $con); return $res->res->rid0->id; } // ADITION 10/06/2008 #\_ Função q retorna uma query de busca montada com os campos pedidos function searchqry($k, $campos) { if($k == '') return ''; $qry = ' AND ('; $k = str_replace(' ', '%', $k); foreach($campos as $c) { $qry .= "`$c` LIKE '%$k%' OR `$c` LIKE '%$k' OR `$c` LIKE '$k%' OR "; } $qry = substr($qry, 0, -4).')'; return $qry; } #\_ Função q retorna o próximo autoindex function nextindex($table, $con) { $res = mysql_query('SHOW TABLE STATUS LIKE "'.$table.'"', $this->con->$con); $rows = mysql_fetch_assoc($res); if(isset($rows['Auto_increment'])) return $rows['Auto_increment']; return $rows['auto_increment']; } #\_ Função para realizar backup no serviço de backup function do_backup($sql, $con) { if(!$this->backup_enabled) return false; if(!BACKUP) return false; $backup = false; $mirror = false; $user = isset($_SESSION['DEFAULT']['userid'])?$_SESSION['DEFAULT']['userid']:0; $sql = trim($sql); if(empty($GLOBALS['mod'])) return false; $sql_original = $sql; $sql = str_replace('`', '', $sql); if(substr($sql, 0, 6) == "UPDATE") { $backup = true; $mirror = true; $table = substr($sql, 7, strpos($sql, ' ', 7)-7); $backup_query = 'SELECT * FROM '.$table. ' '.substr($sql, strpos($sql, 'WHERE')); } if(substr($sql, 0, 6) == "DELETE") { $backup = true; $mirror = true; $table = substr($sql, 12, strpos($sql, ' ', 12)-12); $backup_query = 'SELECT * '.substr($sql, 7); } if(substr($sql, 0, 6) == "INSERT") { $mirror = true; $table = substr($sql, 12, strpos($sql, ' ', 12)-12); } $sql = $sql_original; // espalha pelos mirrors if($mirror and $con == SQL_CON and defined('GLOBAL') and $table != 'global_mirror') { $qry = "INSERT INTO `global_mirror` (`data`, `sql`) VALUES (NOW(), '".base64_encode($sql)."')"; bd_executa($qry, $con); } // salva cópia de segurança if($backup) { $bak = bd_executa($backup_query, $con); if(!$bak->nada) { $GLOBALS['BackupService']->send( array('usuario' => $user, 'tabela' => $table, 'data' => serialize($bak->res)) ); } } } } ############################################################################ ?>method = $method; $this->fmnome = $nome; $this->output = $output; $this->estilo = $estilo; $this->cab = $cab; $this->tags = (object) array(); $this->verificar = array(); $this->ut8_encoded = !($output=='alert'); $param = ''; if($file) $param .= " enctype=\"multipart/form-data\""; if($this->cab) $this->js = ""; if($new_block != NULL) $tpl->newBlock($new_block); if($print_javascript) $tpl->assign('javascript', $this->js); foreach($this->tags as $k => $tag) { $tpl->assign($k, $tag); } $tpl->assign('form_close', ''); } #\_ Função que cria um botão de submit (submit ou image) public function create_tag_submit($nome, $label, $img = "", $param = "") { if($img != "") $this->tags->$nome = ""; else $this->tags->$nome = "estilo["submit"]."\" $param>"; } #\_ Função que cria um campo de verificação capctha public function create_tag_captcha($nome, $label, $params=NULL) { $this->verificar[] = array($nome, $label, array('texto')); $class_normal = $this->estilo['input']; $class_onerror = $this->estilo['input_onerror']; $this->tags->$nome = ' '; } #\_ Função que cria um campo texto (text) public function create_tag_text($nome, $label, $size, $max_size, $valor_inicial='', $verificacao=array('texto'), $params='', $class_normal=NULL, $class_onerror=NULL) { if(!empty($_POST[$nome])) $valor_inicial = $_POST[$nome]; $this->verificar[] = array($nome, $label, $verificacao); if($class_normal == NULL) $class_normal = $this->estilo['input']; if($class_onerror == NULL) $class_onerror = $this->estilo['input_onerror']; $this->tags->$nome = ''; return $this->tags->$nome; } #\_ Função que cria um campo texto com valor inicial inválido para verificação public function create_tag_text_ini($nome, $label, $size, $max_size, $valor_inicial='', $verificacao=array('texto'), $params='', $class_normal=NULL, $class_onerror=NULL) { $this->verificar[] = array($nome, $label, $verificacao, $valor_inicial); $params = ' onfocus="'."if(this.value=='".$valor_inicial."'){this.value='';};".'" onblur="'."if(this.value==''){this.value='".$valor_inicial."';};".'" ' . $params; if(!empty($_POST[$nome])) $valor_inicial = $_POST[$nome]; if($class_normal == NULL) $class_normal = $this->estilo['input']; if($class_onerror == NULL) $class_onerror = $this->estilo['input_onerror']; $this->tags->$nome = ''; return $this->tags->$nome; } #\_ Função que cria um campo de senha (text) function create_tag_password($nome, $label, $size, $max_size, $valor_inicial='', $verificacao=array('texto'), $params='', $class_normal=NULL, $class_onerror=NULL) { if(!empty($_POST[$nome])) $valor_inicial = $_POST[$nome]; $this->verificar[] = array($nome, $label, $verificacao); if($class_normal == NULL) $class_normal = $this->estilo['input']; if($class_onerror == NULL) $class_onerror = $this->estilo['input_onerror']; $this->tags->$nome = ''; return $this->tags->$nome; } #\_ Função que cria um campo de senha com valor inicial inválido para verificação function create_tag_password_ini($nome, $label, $size, $max_size, $valor_inicial='', $verificacao=array('texto'), $params='', $class_normal=NULL, $class_onerror=NULL) { $this->verificar[] = array($nome, $label, $verificacao, $valor_inicial); $params = ' onfocus="'."if(this.value=='".$valor_inicial."'){this.value='';};".'" onblur="'."if(this.value==''){this.value='".$valor_inicial."';};".'" ' . $params; if(!empty($_POST[$nome])) $valor_inicial = $_POST[$nome]; if($class_normal == NULL) $class_normal = $this->estilo['input']; if($class_onerror == NULL) $class_onerror = $this->estilo['input_onerror']; $this->tags->$nome = ''; return $this->tags->$nome; } #\_ Função que cria um campo radio (radio) function create_tag_radio($nome, $lbl, $vlr, $sel = "", $param = "") { global $_POST; $checked = false; if(isset($_POST) and !empty($_POST["$nome"])) { if($_POST["$nome"] == $valor) $checked = "checked"; } elseif($sel) $checked = "checked"; $ret = ""; $this->tags->$lbl = $ret; return $ret; } #\_ Função que cria uma caixa de seleção (checkbox) function create_tag_chbox($nome, $lbl, $vlr, $sel = "", $param = "") { global $_POST; if(isset($_POST) and strtoupper($this->method) == 'POST') { if($_POST["$nome"] == $vlr) $checked = "checked"; } elseif($sel) $checked = "checked"; $this->tags->$nome = ""; return $this->tags->$nome; } #\_ Função que cria um campo escondido (hidden) function create_tag_hidden($nome, $vlr) { $this->tags->$nome = ""; return $this->tags->$nome; } #\_ Função que cria uma combo (select) function create_tag_select($nome, $label, $valores=array(), $valor_inicial='', $dica='', $params='', $verificacao=array('texto'), $class_normal=NULL, $class_onerror=NULL, $multiple=NULL ) { $this->verificar[] = array($nome, $label, $verificacao); if($class_normal == NULL) $class_normal = $this->estilo['select']; if($class_onerror == NULL) $class_onerror = $this->estilo['select_onerror']; $name = $nome; if($multiple != NULL) { $name .= '[]'; $params .= ' multiple="true" size="'.$multiple.'"'; } $tag = '\n"; $this->tags->$nome = $tag; return $tag; } #\_ Função que cria uma área texto (textarea) function create_tag_textarea($nome, $label, $cols, $rows, $valor_inicial='', $verificacao=array('texto'), $params='', $class_normal=NULL, $class_onerror=NULL) { if(!empty($_POST[$nome])) $valor_inicial = $_POST[$nome]; $this->verificar[] = array($nome, $label, $verificacao, $valor_inicial); if($class_normal == NULL) $class_normal = $this->estilo['textarea']; if($class_onerror == NULL) $class_onerror = $this->estilo['textarea_onerror']; $this->tags->$nome = ''; return $this->tags->$nome; } #\_ Função que cria um campo file function create_tag_file($nome, $lbl, $sze, $param = "") { $this->tags->$nome = "estilo["input"]."\" $param>"; } } ############################################################################ ?> $e) { $new_data .= $k.'='.urlencode($e).'&'; } $data = substr($new_data, 0, -1); } unset($k, $e, $new_data); $sock = fsockopen($host, 80, $errorn, $errorstr); if (!$sock) return false; if($fakehost != NULL) $host = $fakehost; $requestHeader = $method." ".$path." HTTP/1.1".$new_line; $requestHeader.= "Host: ".$host.$new_line; $requestHeader.= "Accept: */*".$new_line; $requestHeader.= "User-Agent: z1panel/PluGzOne".$new_line; if ($method == "POST") { $requestHeader.= "Content-Length: ".strlen($data).$new_line; $requestHeader.= "Content-Type: application/x-www-form-urlencoded".$new_line; } foreach($headers as $h) $requestHeader.= $h.$new_line; $requestHeader.= $new_line; if ($method == "POST") $requestHeader.= $data; fwrite($sock, $requestHeader); $output = ''; while (!feof($sock)) { $reply = fgets($sock, 128); if($reply !== false) $output .= $reply; } fclose($sock); if(strpos($output, 'Transfer-Encoding: chunked') !== false) { $chunk_data = substr($output, strpos($output, $new_line.$new_line)+$new_line_len+$new_line_len); $chunk_all = ''; $chunk_size = 0; do { $end_of_line = strpos($chunk_data, $new_line); if($end_of_line !== false) { $chunk_size = substr($chunk_data, 0, $end_of_line); $comment = strpos($chunk_size, ";"); if($comment !== false) $chunk_size = substr($chunk_size, 0, $comment); $chunk_size = hexdec($chunk_size); $chunk_all .= substr($chunk_data, $end_of_line+$new_line_len, $chunk_size); $chunk_data = substr($chunk_data, $end_of_line+$new_line_len+$chunk_size); } } while($chunk_size != 0); $output = substr($output, 0, strpos($output, $new_line.$new_line)+$new_line_len+$new_line_len).$chunk_all; } return $output; } #\_ Realiza uma requisição SSL sem verificação nenhuma / opção de host falso function httpsRequest($host, $path='/', $data=NULL, $headers=array(), $fakehost=NULL) { $uri = 'https://'.$host.$path; $headers[] = 'User-Agent: z1panel/PluGzOne'; if(!function_exists('curl_init')) return httpRequest($host, $path, $data, $headers, $fakehost); $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $uri); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLINFO_HEADER_OUT, true); curl_setopt($curl, CURLOPT_HEADER, true); curl_setopt($curl, CURLOPT_HTTPHEADER, $headers ); curl_setopt($curl, CURLOPT_TIMEOUT, 30); if($data != NULL) { curl_setopt ($curl, CURLOPT_POST, true); curl_setopt ($curl, CURLOPT_POSTFIELDS, $data); } $output = curl_exec($curl); curl_close($curl); return $output; } #\_ Função para recuperar body do replay function httpReplyBody($str) { $tmp = explode("\r\n\r\n", $str); if(is_array($tmp)) { foreach($tmp as $k => $e) { if(substr($e, 0 ,9) == 'HTTP/1.1 ') { unset($tmp[$k]); } } } return implode("\r\n\r\n", $tmp); } ############################################################################ ?>txt = ''.NL; else $this->txt = ''; $this->addTag($main, false, $main_atributos); } #\_ Adiciona uma tag ao corpo do xml function addTag($name, $value=false, $atributos=array(), $full=true) { $this->txt .= $this->getIndent().'<'.$name; // insere inicio da tag if(is_array($atributos)) { foreach($atributos as $k => $e) $this->txt .= ' '.$k.'="'.$this->escape($e).'"'; // insere os atributos } if($full) { if(!$value) { $this->txt .= '>'.NL; array_unshift($this->close, $name); $this->indent++; } else $this->txt .= '>'.$this->escape($value).''.NL; } else $this->txt .= ' />'.NL; } #\_ Escapa a string xml private function escape($str) { return str_replace('&', '&amp;', ($str) ); } #\_ Retorna o indent eoutdent atual private function getIndent() { $t = ''; for( $i=0; $i<$this->indent ; $i++ ) $t .= "\t"; return $t; } #\_ Fecha última tag function closeTag() { $this->indent--; $this->txt .= $this->getIndent().'close).'>'.NL; } #\_ Retorna o processamento do xml function retorna() { while(count($this->close) > 0) $this->closeTag(); return $this->txt; } function __toString() { return $this->retorna(); } #\_ Parser de XML para Array public static function toRay($fileName, $file=true, $includeTopTag = false, $lowerCaseTags = true) { if (!$file) $fileContent = $fileName; else $fileContent = file_get_contents($fileName); $p = xml_parser_create('ISO-8859-1'); xml_parse_into_struct($p, $fileContent, $vals, $index); xml_parser_free($p); $xml = array(); $levels = array(); $multipleData = array(); $prevTag = ""; $currTag = ""; $topTag = false; foreach ($vals as $val) { // Open tag if ($val["type"] == "open") { if (!self::_xmlFileToArrayOpen($topTag, $includeTopTag, $val, $lowerCaseTags, $levels, $prevTag, $multipleData, $xml)) continue; } // Close tag elseif ($val["type"] == "close") { if (!self::_xmlFileToArrayClose($topTag, $includeTopTag, $val, $lowerCaseTags, $levels, $prevTag, $multipleData, $xml)) continue; } // Data tag elseif ($val["type"] == "complete" && isset($val["value"])) { $loc =& $xml; foreach ($levels as $level) { $temp =& $loc[str_replace(":arr#", "", $level)]; $loc =& $temp; } $tag = $val["tag"]; if ($lowerCaseTags) $tag = strtolower($val["tag"]); $loc[$tag] = str_replace("\\n", "\n", $val["value"]); } // Tag without data elseif ($val["type"] == "complete") { self::_xmlFileToArrayOpen($topTag, $includeTopTag, $val, $lowerCaseTags, $levels, $prevTag, $multipleData, $xml); self::_xmlFileToArrayClose($topTag, $includeTopTag, $val, $lowerCaseTags, $levels, $prevTag, $multipleData, $xml); } } return $xml; } private static function _xmlFileToArrayOpen(& $topTag, & $includeTopTag, & $val, & $lowerCaseTags, & $levels, & $prevTag, & $multipleData, & $xml) { // don't include top tag if (!$topTag && !$includeTopTag) { $topTag = $val["tag"]; return false; } $currTag = $val["tag"]; if ($lowerCaseTags) $currTag = str_replace(':', '', strtolower($val["tag"]) ); $levels[] = $currTag; // Multiple items w/ same name. Convert to array. if ($prevTag === $currTag) { if (!array_key_exists($currTag, $multipleData) || !$multipleData[$currTag]["multiple"]) { $loc =& $xml; foreach ($levels as $level) { $temp =& $loc[$level]; $loc =& $temp; } $loc = array($loc); $multipleData[$currTag]["multiple"] = true; $multipleData[$currTag]["multiple_count"] = 0; } $multipleData[$currTag]["popped"] = false; $levels[] = ":arr#" . ++$multipleData[$currTag]["multiple_count"]; } else $multipleData[$currTag]["multiple"] = false; // Add attributes array if (array_key_exists("attributes", $val)) { $loc =& $xml; foreach ($levels as $level) { $temp =& $loc[str_replace(":arr#", "", $level)]; $loc =& $temp; } $keys = array_keys($val["attributes"]); foreach ($keys as $key) { $tag = $key; if ($lowerCaseTags) $tag = str_replace(':', '', strtolower($tag) ); $loc["attributes"][$tag] = & $val["attributes"][$key]; } } return true; } private static function _xmlFileToArrayClose(& $topTag, & $includeTopTag, & $val, & $lowerCaseTags, & $levels, & $prevTag, & $multipleData, & $xml) { if ($topTag && !$includeTopTag && $val["tag"] == $topTag) return false; if(isset($currTag)) { if ($multipleData[$currTag]["multiple"]) { $tkeys = array_reverse(array_keys($multipleData)); foreach ($tkeys as $tkey) { if ($multipleData[$tkey]["multiple"] && !$multipleData[$tkey]["popped"]) { array_pop($levels); $multipleData[$tkey]["popped"] = true; break; } elseif (!$multipleData[$tkey]["multiple"]) break; } } } $prevTag = array_pop($levels); if (strpos($prevTag, "arr#")) $prevTag = array_pop($levels); return true; } } ############################################################################ ?>