0byt3m1n1
Path:
/
data
/
applications
/
aps
/
tikiwiki
/
14.1-0
/
standard
/
htdocs
/
lib
/
wiki-plugins
/
[
Home
]
File: wikiplugin_dbreport.php
<?php // (c) Copyright 2002-2015 by authors of the Tiki Wiki CMS Groupware Project // // All Rights Reserved. See copyright.txt for details and a complete list of authors. // Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. // $Id: wikiplugin_dbreport.php 56266 2015-09-20 16:56:57Z lindonb $ $wikiplugin_dbreport_errors; $wikiplugin_dbreport_fields; $wikiplugin_dbreport_fields_allowed; $wikiplugin_dbreport_record; class WikipluginDBReportToken { public $type; // key=keyword, fld=field, str=string, var=variable, sty=style, eof=end of file public $content; public $start; public $after; public $code; public function type_name() { switch($this->type) { case 'key': return 'Keyword'; case 'txt': return 'Text'; case 'sty': return 'Style'; case 'fld': return 'Field'; case 'var': return 'Variable'; case 'str': return 'String'; case 'bra': return 'Brackets'; case 'eof': return 'End'; default: return $token->type; } } public function WikipluginDBReportToken($content=null) { $this->content = $content; } } class WikipluginDBReportField { public $name; public $variable; public $break; public $index; public function WikipluginDBReportField($text) { global $wikiplugin_dbreport_fields, $wikiplugin_dbreport_fields_allowed; $this->name = stripcslashes($text); if ($text[0]=='$') { $this->variable = substr($this->name, 1); // print("new variable $this->variable "); } else { // add to the list of parsed fields // if ($wikiplugin_dbreport_fields_allowed) $wikiplugin_dbreport_fields[] =& $this; } } public function text() { global $wikiplugin_dbreport_record; if (isset($this->index)) { // indexed field return (string) ($wikiplugin_dbreport_record[$this->index]); } else if (isset($this->variable)) { // PHP variable if (isset($GLOBALS[$this->variable])) { return (string) $GLOBALS[$this->variable]; } elseif (isset($_SESSION[$this->variable])) { return (string) $_SESSION[$this->variable]; } else if (isset($_REQUEST[$this->variable])) { return (string) $_REQUEST[$this->variable]; } } else { return "[$this->name]"; } } public function code() { if (isset($this->variable)) { return '[$' . addcslashes($this->variable, "\0..\37[]$\\") . ']'; } else { return '[' . addcslashes($this->name, "\0..\37[]$\\") . ']'; } } public function html() { return htmlentities($this->text()); } public function uri() { return urlencode($this->text()); } } class WikipluginDBReportString { public $literal; public function WikipluginDBReportString($text) { $this->literal = stripcslashes($text); } public function text() { return $this->literal; } public function code() { return addcslashes($this->literal, "\0..\37[]\\"); } public function html() { return htmlentities($this->text()); } public function uri() { return $this->text(); } } class WikipluginDBReportContent { public $elements; public function parse_text(&$text) { $parse_state = 0; $parse_text = ''; $pos = 0; $len = strlen($text); while ($pos < $len) { $char = $text[$pos++]; switch($parse_state) { case 0: // start of next token switch($char) { case '[': $parse_state = 3; break; case '\\': $parse_state = 2; $parse_text .= $char; break; default: $parse_state = 1; $parse_text .= $char; } break; case 1: // text string switch($char) { case '[': unset($this->elements); $this->elements[] = new WikipluginDBReportString($parse_text); $parse_text = ''; $parse_state = 3; break; case '\\': $parse_state = 2; $parse_text .= $char; break; default: $parse_text .= $char; } break; case 2: // literal escape $parse_text .= $char; $parse_state = 1; break; case 3: // field text switch($char) { case '[': break; case ']': unset($this->elements); $this->elements[] = new WikipluginDBReportField($parse_text); $parse_text = ''; $parse_state = 0; break; case '\\': $parse_state = 4; $parse_text .= $char; break; default: $parse_text .= $char; } break; case 4: // field escape $parse_text .= $char; $parse_state = 3; break; } } // hanging text is parsed as a string if ($parse_state!=0) { unset($this->elements); $this->elements[] = new WikipluginDBReportString($parse_text); } } public function append_field($name) { unset($this->elements); $this->elements[] = new WikipluginDBReportField($name); } public function append_variable($name) { unset($this->elements); $this->elements[] = new WikipluginDBReportField('$'.$name); } public function append_string($text) { unset($this->elements); $this->elements[] = new WikipluginDBReportString($text); } public function append($text) { $this->parse_text($text); } public function WikipluginDBReportContent(&$token) { switch($token->type) { case 'txt': $this->parse_text($token->content); break; case 'fld': $this->append_field($token->content); break; case 'var': $this->append_variable($token->content); break; } } public function text() { $result = ''; if (isset($this->elements)) { foreach ($this->elements as $element) { $result .= $element->text(); } } return $result; } public function code() { $result = ''; if (isset($this->elements)) { foreach ($this->elements as $element) { $result .= $element->code(); } } return $result; } public function html() { $result = ''; if (isset($this->elements)) { foreach ($this->elements as $element) { $result .= $element->html(); } } return $result; } public function uri() { $result = ''; if (isset($this->elements)) { foreach ($this->elements as $element) { $result .= $element->uri(); } } return $result; } } class WikipluginDBReportText extends WikipluginDBReportContent { public $link; public $style; public function code() { $result = '"' . addcslashes(parent::code(), '"') . '"'; if (isset($this->style)) { $result .= $this->style->code(); } if (isset($this->link)) { $result .= ' '.$this->link->code(); } return $result; } public function html() { $html = parent::html(); if (isset($this->style)) { $html = $this->style->html_start() . $html . $this->style->html_end(); } if (isset($this->link)) { $html = $this->link->html_start() . $html . $this->link->html_end(); } return $html; } } class WikipluginDBReportStyle { public $tag; public $class; public $style; public function WikipluginDBReportStyle(&$token) { if (is_object($token)) { if ($token->content['class']) { $subtoken =& $token->content['class']; unset($this->class); $this->class = new WikipluginDBReportContent($subtoken); } if ($token->content['style']) { $subtoken =& $token->content['style']; unset($this->style); $this->style = new WikipluginDBReportContent($subtoken); } } else if (is_string($token)) { unset($subtoken); $subtoken = new WikipluginDBReportToken($token); $subtoken->type = 'txt'; unset($this->class); $this->class = new WikipluginDBReportContent($subtoken); } } public function code() { $code = ':'; if (isset($this->class)) { $code .= addcslashes($this->class->code(), ' '); } else if ($this->tag!='span') { $code .= $this->tag; } // if (isset($this->class)) $code .= $this->class->code(); if (isset($this->style)) { $code .= "{" . $this->style->code() . "}"; } return $code; } public function attributes() { if (isset($this->class)) { $html .= ' class="' . $this->class->html() . '"'; } if (isset($this->style)) { $html .= ' style="' . $this->style->html() . '"'; } return $html; } public function html_start() { if (isset($this->class)) { $class = $this->class->html(); switch(strtolower($class)) { case 'u': case 'b': case 'i': case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6': $this->tag = $class; $html = '<' . $class; break; default: $this->tag = 'span'; $html = '<span class="' . $class . '"'; } } else { $this->tag = 'span'; $html = '<span'; } if (isset($this->style)) { $html .= ' style="' . $this->style->html() . '"'; } $html .= '>'; return $html; } public function html_end() { return '</'.$this->tag.'>'; } } class WikipluginDBReportLink { public $style; public $contents; public function code() { $result = '<'; if (isset($this->contents)) { foreach ($this->contents as $content) { if (is_a($content, 'WikipluginDBReportContent')) { $result .= '"'.$content->code().'"'; } else if (is_a($content, 'WikipluginDBReportField')) { $result .= $content->code(); } } } if (isset($this->style)) { $result .= $this->style->code(); } $result .= '>'; return $result; } public function uri() { if (isset($this->contents)) { foreach ($this->contents as $content) { if (is_a($content, 'WikipluginDBReportContent')) { $uri .= $content->html(); } else if (is_a($content, 'WikipluginDBReportField')) { $uri .= $content->uri(); } } } return $uri; } public function html_start() { $html = '<a href="' . $this->uri() . '"'; if ($this->style) { $html .= $this->style->attributes(); } $html .= '>'; return $html; } public function html_end() { return '</a>'; } public function html_onclick() { return 'onclick="document.location.href="' . $this->uri() . '""'; } } class WikipluginDBReportCell { public $link; public $style; public $colspan; public $rowspan; public $contents; public function code($mode) { $result = 'CELL'; if (isset($this->colspan) && isset($this->rowspan)) { if ($this->rowspan!=1) { $result .= ' ROWSPAN '.$this->rowspan; } if ($this->colspan!=1) { $result .= ' COLSPAN '.$this->colspan; } } else if (isset($this->colspan)) { if ($this->colspan!=1) { if ($mode=='ROW') { $result .= ' SPAN '.$this->colspan; } else { $result .= ' COLSPAN '.$this->colspan; } } } else if (isset($this->rowspan)) { if ($this->rowspan!=1) { if ($mode=='ROW') { $result .= ' ROWSPAN '.$this->rowspan; } else { $result .= ' SPAN '.$this->rowspan; } } } if (isset($this->style)) { $result .= ' ' . $this->style->code(); } if (isset($this->link)) { $result .= ' ' . $this->link->code(); } if (isset($this->contents)) { foreach ($this->contents as $content) { $result .= ' '.$content->code(); } } return $result; } public function html($heading=false) { if ($heading) { $html = '<th'; } else { $html = '<td'; } if (isset($this->style)) { $html .= $this->style->attributes(); } if (isset($this->rowspan)) { $html .= ' rowspan="' . $this->rowspan . '"'; } if (isset($this->colspan)) { $html .= ' colspan="' . $this->colspan . '"'; } if (isset($this->link)) { $html .= ' ' . $this->link->html_onclick(); } $html .= '>'; if (isset($this->contents)) { foreach ($this->contents as $content) { $html .= $content->html(); } } $html .= '</td>'; return $html; } } class WikipluginDBReportLine { public $link; public $styles; public $cells; public function code($indent='',$rtype='ROW',$cellmode='ROW') { $result = $indent.$rtype; if (isset($this->styles)) { foreach ($this->styles as $style) { $result .= ' '.$style->code(); } } if (isset($this->link)) { $result .= ' '.$this->link->code(); } $result .= "\n"; foreach ($this->cells as $cell) { $result .= $indent.' '.$cell->code($cellmode)."\n"; } return $result; } public function row_html($data,$style,$heading=false) { // set the global report row global $wikiplugin_dbreport_record; $wikiplugin_dbreport_record = $data; // generate HTML $html = '<tr'; if (isset($style)) { $html .= $style->attributes(); } if (isset($this->link)) { $html .= ' ' . $this->link->html_onclick(); } $html .= '>'; foreach ($this->cells as $cell) { $html .= $cell->html($heading); } $html .= '</tr>' . "\n"; return $html; } } class WikipluginDBReportTable { public $style; public $headers; public $rows; public $footers; public $style_index; public function code($indent='') { $result = $indent.'TABLE'; if (isset($this->style)) { $result .= ' '.$this->style->code(); } $result .= "\n"; if (isset($this->headers)) { foreach ($this->headers as $line) { $result .= $line->code($indent.' ', 'HEADER'); } } if (isset($this->rows)) { foreach ($this->rows as $line) { $result .= $line->code($indent.' ', 'ROW'); } } if (isset($this->footers)) { foreach ($this->footers as $line) { $result .= $line->code($indent.' ', 'FOOTER'); } } return $result; } public function line_row_html($list,$data,$heading=false) { $html = ''; foreach ($list as $line) { $style = null; if (isset($line->styles)) { $style_count = count($line->styles); $style = $line->styles[$this->style_index % $style_count]; } $html .= $line->row_html($data, $style, $heading); } return $html; } public function header_row_html($data) { $html = ''; // generate a new table if (isset($this->style)) { $html .= '<table' . $this->style->attributes() . '>' . "\n"; } else { $html .= '<table>' . "\n"; } // write headers $style_index = 0; if (isset($this->headers)) { $html .= $this->line_row_html($this->headers, $data, true); } return $html; } public function record_row_html($data) { $html = ''; if (isset($this->rows)) { $html .= $this->line_row_html($this->rows, $data); } $this->style_index++; return $html; } public function footer_row_html($data) { $html = ''; // write footers $this->style_index = 0; if (isset($this->footers)) { $html .= $this->line_row_html($this->footers, $data, true); } // close the table $html .= '</table>'; return $html; } } class WikipluginDBReportGroup { public $link; public $style; public $fields; public $field_count; public $contents; public function __toString() { $result = ''; foreach ($this->contents as $entry) { $result .= $entry; } return $result; } public function code($indent='') { $result = $indent.'GROUP'; if (isset($this->style)) { $result .= ' '.$this->style->code(); } if (isset($this->fields)) { foreach ($this->fields as $field) { $result .= ' '.$field->code(); } } if (isset($this->link)) { $result .= ' '.$this->link->code(); } if (isset($this->contents)) { foreach ($this->contents as $content) { $result .= ' '.$content->code(); } } $result .= "\n"; return $result; } public function check_break(&$row) { $ret = false; // compare the field values against the break values for ($i=0; $i<$this->field_count; $i++) { $field =& $this->fields[$i]; $value =& $row[$field->index]; if ($value !== $field->break) { $ret = true; $field->break =& $value; } } return $ret; } public function start_html($row) { global $wikiplugin_dbreport_record; $wikiplugin_dbreport_record = $row; $html = ''; // generate a new <div> with the report content at the top if (isset($this->style)) { $html .= '<div' . $this->style->attributes() . '>' . "\n"; } else { $html .= '<div>' . "\n"; } if (isset($this->contents)) { foreach ($this->contents as $content) { $html.= $content->html(); } } return $html; } public function end_html(&$row) { $html = ''; // close the <div> $html .= '</div>'; return $html; } } class WikipluginDBReportParameter extends WikipluginDBReportContent { public $name; public function code($indent='') { $result = $indent.'PARAM'; // if (isset($this->name)) $result .= ' :'.$this->name; if (isset($this->elements)) { foreach ($this->elements as $element) { $result .= ' ' . $element->code(); } } $result .= "\n"; // $result .= ' "' . parent::code() . "\"\n"; return $result; } } class WikipluginDBReportFail { public $link; public $style; public $contents; public function code($mode) { $result = 'FAIL'; if (isset($this->style)) { $result .= ' ' . $this->style->code(); } if (isset($this->link)) { $result .= ' ' . $this->link->code(); } if (isset($this->contents)) { foreach ($this->contents as $content) { $result .= ' '.$content->code(); } } return $result; } public function html($heading=false) { $html = '<div'; if (isset($this->style)) { $html .= $this->style->attributes(); } if (isset($this->link)) { $html .= ' ' . $this->link->html_onclick(); } $html .= '>'; if (isset($this->contents)) { foreach ($this->contents as $content) { $html .= $content->html(); } } $html .= '</div>'; return $html; } } class WikipluginDBReport { public $sql; public $params; public $groups; public $table; public $columns; public $fail; public function code($indent='') { // write the report in cannonical form. $result = $indent.'SQL {' . $this->sql . '}'."\n"; if (isset($this->params)) { foreach ($this->params as $param) { $result .= $param->code($indent.' '); } } if (isset($this->groups)) { foreach ($this->groups as $group) { $result .= $group->code($indent); } } if (isset($this->table)) { $result .= $this->table->code($indent); } if (isset($this->fail)) { $result .= $this->fail->code($indent); } return $result; } } function wikiplugin_dbreport_parse_error(&$token, $msg) { global $wikiplugin_dbreport_errors; // find the line relating to the token in the code $pos = 0; $line = 0; $code =& $token->code; $len = strlen($code); while ($pos<$len) { // find the next line break $line++; $break = strpos($code, "\n", $pos); if ($break===false) { $break = $len; } // was the token in this line? if ($token->start < $break) { // format the line with the token highlighted $err_line = '<i>line '.$line.'</i>: '; $err_line .= substr($code, $pos, $token->start-$pos); $err_line .= '<span style="font-weight:bold;color:DarkRed;">'.substr($code, $token->start, $token->after-$token->start).'</span>'; if ($token->after<$break) { $err_line .= substr($code, $token->after, $break-$token->after); } $wikiplugin_dbreport_errors[] = $err_line; $pos = $len; } else { // update position and loop $pos = $break + 1; } } // add the message to the errors $wikiplugin_dbreport_errors[] = $msg; } function wikiplugin_dbreport_next_token(&$code, $len, $pos) { global $wikiplugin_dbreport_errors, $wikiplugin_dbreport_fields_allowed; $whitespace = " \n\r\t\v\f"; $tokenstop = " :<>[$\"\n\r\t\v\f"; // create a token object to return unset($token); $token = new WikipluginDBReportToken(); $token->code =& $code; // find the next non-whitespace character in the code while ( ($pos < $len) && (strpos($whitespace, $code[$pos])!==false) ) { $pos++; } if ( $pos >= $len ) { $token->type = 'eof'; $token->start = $len - 1; $token->after = $pos; return $token; } // what did we find? switch($code[$pos]) { case '[': // field token $token->start = $pos; // parse to closing ']' while ( ($pos < $len) && ($code[$pos]!=']') ) { if ($code[$pos]=='\\') { $pos++; } $pos++; } if ($pos < $len) { $token->after = ++$pos; $token->type = 'fld'; $token->content = substr($code, $token->start+1, $pos-$token->start-2); return $token; } else { $token->after = ++$pos; $token->type = 'eof'; wikiplugin_dbreport_parse_error($token, "Unclosed Field. ] expected."); return $token; } break; case '{': // brackets token $token->type = 'bra'; $token->start = $pos; // parse until we find the closing bracket. $pos++; $state = 0; while ( ($pos < $len) && ($state<4) ) { $c = $code[$pos++]; switch($state) { case 0: // normal content switch($c) { case '}': $state = 4; break; case '`': $state = 1; $token->content .= $c; break; case "'": $state = 2; $token->content .= $c; break; case '"': $state = 3; $token->content .= $c; break; default: $token->content .= $c; } break; case 1: // backtick-quoted switch($c) { case '`': $state = 0; default: $token->content .= $c; } break; case 2: // single-quoted switch($c) { case '\\': $token->content .= $c . $code[$pos++]; break; case '\'': $state = 0; default: $token->content .= $c; } break; case 3: // double-quoted switch($c) { case '\\': $token->content .= $c . $code[$pos++]; break; case '"': $state = 0; default: $token->content .= $c; } break; } } $token->after = $pos; switch($state) { case 0: // unclosed brackets wikiplugin_dbreport_parse_error($token, "Unclosed brackets. } expected"); $token->type = 'eof'; break; case 1: // unclosed backtick-quoted content wikiplugin_dbreport_parse_error($token, "Unclosed backtick-quoted content in brackets. ` then } expected"); $token->type = 'eof'; break; case 2: // unclosed single-quoted content wikiplugin_dbreport_parse_error($token, "Unclosed single-quoted content in brackets. ' then } expected"); $token->type = 'eof'; break; case 3: // unclosed double-quoted content wikiplugin_dbreport_parse_error($token, "Unclosed double-quoted content in brackets. \" then } expected"); $token->type = 'eof'; break; } return $token; break; case ':': // style token $token->type = 'sty'; $token->start = $pos; $token->content = array(); // create content sub-tokens unset($class); $class = new WikipluginDBReportToken(); $class->code =& $code; $class->type = 'txt'; $class->start = $pos; unset($style); $style = new WikipluginDBReportToken(); $style->code =& $code; $style->type = 'txt'; // parse until we find the closing space. $pos++; $state = 0; while ( ($pos < $len) && ($state<6) ) { $c = $code[$pos++]; if ($c=='\\') { $c .= $code[$pos++]; $tc = $c; } else { $tc = strpos($whitespace, $c)!==false ? ' ': $c; } switch($state) { case 0: // class content switch($tc) { case '<': case '>': case '"': case ' ': $state = 6; $class->after = $pos; break; case '{': $state = 1; $class->after = $pos; $style->start = $pos-1; break; case '[': $state = 2; default: $class->content .= $c; } break; case 1: // inline style content switch($tc) { case '}': $state = 6; $style->after = $pos; break; case '[': $state = 3; $style->content .= $c; break; case "'": $state = 4; $style->content .= $c; break; case '"': $state = 5; $style->content .= $c; break; default: $style->content .= $c; } break; case 2: // class field switch($tc) { case ']': $state = 0; default: $class->content .= $c; } break; case 3: // inline style field switch($tc) { case ']': $state = 1; default: $style->content .= $c; } break; case 4: // single-quoted inline style switch($tc) { case '\'': $state = 1; default: $style->content .= $c; } break; case 5: // double-quoted inline style switch($tc) { case '"': $state = 1; default: $style->content .= $c; } break; } } switch($state) { case 0: // end of file $class->after = $pos; break; case 1: // inline style content $style->after = $pos; wikiplugin_dbreport_parse_error($style, "Unclosed style CSS. } expected"); $token->type = 'eof'; break; case 2: // class field $class->after = $pos; wikiplugin_dbreport_parse_error($class, "Unclosed field in style class. ] expected"); $token->type = 'eof'; break; case 3: // inline style field $style->after = $pos; wikiplugin_dbreport_parse_error($style, "Unclosed field in style CSS. ] then } expected"); $token->type = 'eof'; break; case 4: // single-quoted inline style $style->after = $pos; wikiplugin_dbreport_parse_error($style, "Unclosed single-quoted content in style CSS. ' then } expected"); $token->type = 'eof'; break; case 5: // double-quoted inline style $style->after = $pos; wikiplugin_dbreport_parse_error($style, "Unclosed double-quoted content in style CSS. \" then } expected"); $token->type = 'eof'; break; } if ($class->content) { $token->content['class'] = $class; } if ($style->content) { $token->content['style'] = $style; } $token->after = $pos; return $token; break; case '$': // variable token $token->type = 'var'; $token->start = $pos; $pos++; // parse to end of token while ( ($pos < $len) && (strpos($tokenstop, $code[$pos])===false) ) { if ($code[$pos]=='\\') { $pos++; } $pos++; } $token->content = substr($code, $token->start+1, $pos-$token->start-1); $token->after = $pos; return $token; break; case '"': // string token $token->type = 'txt'; $token->start = $pos; $token->content = ''; // parse until we find the closing quote. $pos++; while ( $pos < $len ) { // what is it? $c = $code[$pos++]; switch($c) { case '"': $token->after = $pos; return $token; break; case '\\': $token->content .= $c; if ( ($pos < $len) ) { $c = $code[$pos++]; $token->content .= $c; } else { wikiplugin_dbreport_parse_error($token, "Unclosed escaped string. \" expected."); $token->type = 'eof'; return $token; } break; default: $token->content .= $c; break; } } // didn't find closing quotes $token->type = 'txt'; wikiplugin_dbreport_parse_error($token, "Unterminated string. \" expected."); $token->type = 'eof'; return $token; break; case '<': case '>': // link keywords $token->type = 'key'; $token->content = $code[$pos]; $token->start = $pos; $token->after = ++$pos; return $token; break; default: // keyword token $token->start = $pos; // parse to end of token while ( ($pos < $len) && (strpos($tokenstop, $code[$pos])===false) ) { $pos++; } $token->type = 'key'; $token->content = substr($code, $token->start, $pos - $token->start); $token->after = $pos; return $token; } } function wikiplugin_dbreport_parse(&$code) { global $debug, $wikiplugin_dbreport_fields_allowed; // code properties $len = strlen($code); $pos = 0; // FSM state $parse_state = 0; $parse_link_return = 0; $parse_line_return = 0; $parse_cell_return = 0; $parse_object; $parse_text; $parse_line; $parse_cell; $span_mode; unset($parse_report); $parse_report = new WikipluginDBReport(); // parse the code while (true) { // get the next token $token = wikiplugin_dbreport_next_token($code, $len, $pos); $pos = $token->after; // repeat while we have an unconsumed token while (isset($token)) { $next_token = $token; switch($parse_state) { case 0: // next keyword switch ($token->type) { case 'eof': if (!isset($parse_report->sql)) { return wikiplugin_dbreport_parse_error($token, "Unexpected End."); } return $parse_report; break; case 'key': switch(TikiLib::strtoupper($token->content)) { case 'SQL': $parse_state = 1; // switch state unset($next_token); // consume the token $wikiplugin_dbreport_fields_allowed = false; // no fields in sql break; case 'PARAM': // create the parameter object unset($parse_object); $parse_object = new WikipluginDBReportParameter($token); $parse_report->params[] =& $parse_object; $parse_state = 2; // switch state unset($next_token); // consume the token $wikiplugin_dbreport_fields_allowed = false; // no fields in sql params break; case 'GROUP': // create the group object unset($parse_object); $parse_object = new WikipluginDBReportGroup(); $parse_report->groups[] =& $parse_object; $parse_state = 3; // switch state unset($next_token); // consume the token $wikiplugin_dbreport_fields_allowed = true; // we can now parse fields break; case 'TABLE': // create the table object unset($parse_object); $parse_object = new WikipluginDBReportTable(); $parse_report->table =& $parse_object; $parse_state = 4; // switch state unset($next_token); // consume the token $wikiplugin_dbreport_fields_allowed = true; // we can now parse fields break; case 'FAIL': // create the fail object unset($parse_object); $parse_object = new WikipluginDBReportFail(); $parse_report->fail =& $parse_object; $parse_state = 10; // switch state unset($next_token); // consume the token $wikiplugin_dbreport_fields_allowed = false; // no fields in fail message break; default: return wikiplugin_dbreport_parse_error($token, "Invalid keyword '$token->content'"); } break; default: return wikiplugin_dbreport_parse_error($token, "Unexpected ".$token->type." '".$token->content."' at ".$token->start); } break; case 1: // SQL content switch($token->type) { case 'eof': $parse_state = 0; // switch state and reparse the token break; case 'bra': $parse_report->sql .= $token->content; unset($next_token); // consume the token break; case 'txt': $parse_report->sql .= stripcslashes($token->content); unset($next_token); // consume the token break; case 'key': $parse_state = 0; // switch state and reparse the token break; default: return wikiplugin_dbreport_parse_error($token, "Unexpected " . $token->type_name() . " '$token->content' after 'SQL'. String expected."); } break; case 2: // PARAM content switch($token->type) { case 'eof': $parse_state = 0; // switch parse state break; /* case 'sty': $parse_object->name = $token->content; unset($next_token); // consume the token break; */ case 'fld': $parse_object->append_field($token->content); unset($next_token); // consume the token break; case 'var': $parse_object->append_variable($token->content); unset($next_token); // consume the token break; case 'txt': unset($parse_object->elements); $parse_object->elements[] = new WikipluginDBReportText($token); unset($next_token); // consume the token break; case 'key': unset($parse_object); $parse_state = 0; // switch state and reparse the token break; default: return wikiplugin_dbreport_parse_error($token, "Unexpected " . $token->type_name() . " '$token->content' after 'PARAM'. Name, Field, String or Variable expected."); } break; case 3: // GROUP content switch($token->type) { case 'eof': $parse_state = 0; // switch state and reparse the token break; case 'fld': unset($parse_object->fields); $parse_object->fields[] = new WikipluginDBReportField($token->content); $parse_object->field_count++; unset($next_token); // consume the token break; case 'txt': case 'var': unset($parse_text); $parse_text = new WikipluginDBReportText($token); $parse_object->contents[] =& $parse_text; $parse_text_return = $parse_state; // return to this state $parse_state = 9; // switch state unset($next_token); // consume the token break; case 'sty': unset($parse_object->style); $parse_object->style = new WikipluginDBReportStyle($token); unset($next_token); // consume the token break; case 'key': switch(TikiLib::strtoupper($token->content)) { case '<': unset($parse_link); $parse_link = new WikipluginDBReportLink($token); // create the link object $parse_object->link =& $parse_link; $parse_link_return = $parse_state; // return to this state $parse_state = 5; // switch state unset($next_token); // consume the token break; default: unset($parse_object); // we are finished parsing the group $wikiplugin_dbreport_fields_allowed = false; // we cannot parse fields anymore $parse_state = 0; // switch state and reparse the token break; } break; default: return wikiplugin_dbreport_parse_error($token, "Unexpected " . $token->type_name() . " '$token->content' after '<'. Field, String or Style expected."); } break; case 4: // TABLE content switch($token->type) { case 'eof': $parse_state = 0; // switch state and reparse the token break; case 'sty': unset($parse_object->style); $parse_object->style = new WikipluginDBReportStyle($token); unset($next_token); // consume the token break; case 'key': switch(TikiLib::strtoupper($token->content)) { case 'HEADER': unset($parse_line); $parse_line = new WikipluginDBReportLine(); $parse_object->headers[] =& $parse_line; $parse_line_return = $parse_state; // return to this state $parse_state = 6; // switch state unset($next_token); // consume the token break; case 'FOOTER': unset($parse_line); $parse_line = new WikipluginDBReportLine(); $parse_object->footers[] =& $parse_line; $parse_line_return = $parse_state; // return to this state $parse_state = 6; // switch state unset($next_token); // consume the token break; case 'ROW': case 'ROWS': unset($parse_line); $parse_line = new WikipluginDBReportLine(); $parse_object->rows[] =& $parse_line; $parse_line_return = $parse_state; // return to this state $parse_state = 6; // switch state unset($next_token); // consume the token break; default: unset($parse_object); // we are finished parsing the table $wikiplugin_dbreport_fields_allowed = false; // we cannot parse fields anymore $parse_state = 0; // switch state and reparse the token } break; default: return wikiplugin_dbreport_parse_error($token, "Unexpected " . $token->type_name() . " '$token->content' after 'TABLE'. HEADER, FOOTER, ROWS, <, or Style expected."); } break; case 5: // Link content switch($token->type) { case 'eof': return wikiplugin_dbreport_parse_error($token, "Unexpected EOF in WikipluginDBReportLink. '>' expected."); break; case 'var': case 'fld': unset($parse_link->contents); $parse_link->contents[] = new WikipluginDBReportField($token->content); unset($next_token); // consume the token break; case 'txt': unset($parse_link->contents); $parse_link->contents[] = new WikipluginDBReportContent($token); unset($next_token); // consume the token break; /* case 'txt': $parse_link->append($token->content); unset($next_token); // consume the token break; case 'var': $parse_link->append_variable($token->content); unset($next_token); // consume the token break; case 'fld': $parse_link->append_field($token->content); unset($next_token); // consume the token break; */ case 'sty': unset($parse_link->style); $parse_link->style = new WikipluginDBReportStyle($token); unset($next_token); // consume the token break; case 'key': switch(TikiLib::strtoupper($token->content)) { case '<': return wikiplugin_dbreport_parse_error($token, "Unexpected '<' in Link. '>' expected."); case '>': unset($next_token); // consume the token $parse_state = $parse_link_return; // return to previous state break; default: return wikiplugin_dbreport_parse_error($token, "Unexpected Keyword '$token->content' in Link. '>' expected."); } default: $parse_state = $parse_link_return; // switch state and reparse the token } break; case 6: // HEADER, FOOTER, ROW content switch($token->type) { case 'eof': $parse_state = $parse_line_return; // switch state and reparse the token break; case 'sty': unset($parse_link->styles); $parse_line->styles[] = new WikipluginDBReportStyle($token); unset($next_token); // consume the token break; case 'key': switch(TikiLib::strtoupper($token->content)) { case 'CELL': unset($parse_cell); $parse_cell = new WikipluginDBReportCell(); $parse_line->cells[] =& $parse_cell; $parse_cell_return = $parse_state; // return to this state $parse_state = 7; // switch state unset($next_token); // consume the token break; case '<': unset($parse_link); $parse_link = new WikipluginDBReportLink($token); // create the link object $parse_line->link =& $parse_link; $parse_link_return = $parse_state; // return to this state $parse_state = 5; // switch state unset($next_token); // consume the token break; case 'HEADER': case 'ROW': case 'FOOTER': case 'FAIL': $parse_state = $parse_line_return; break; default: return wikiplugin_dbreport_parse_error($token, "Invalid keyword '$token->content' after row. CELL or Link expected."); } break; default: return wikiplugin_dbreport_parse_error($token, "Unexpected " . $token->type_name() . " '$token->content' in row."); } break; case 7: // CELL content switch($token->type) { case 'eof': $parse_state = $parse_cell_return; // switch state and reparse the token break; case 'fld': case 'var': case 'txt': unset($parse_text); $parse_text = new WikipluginDBReportText($token); $parse_cell->contents[] =& $parse_text; $parse_text_return = $parse_state; // return to this state $parse_state = 9; // switch state unset($next_token); // consume the token break; case 'sty': unset($parse_cell->style); $parse_cell->style = new WikipluginDBReportStyle($token); unset($next_token); // consume the token break; case 'key': switch(TikiLib::strtoupper($token->content)) { case '<': unset($parse_link); $parse_link = new WikipluginDBReportLink($token); // create the link object $parse_cell->link =& $parse_link; $parse_link_return = $parse_state; // return to this state $parse_state = 5; // switch state unset($next_token); // consume the token break; case 'SPAN': $span_mode = 'COL'; $parse_state = 8; // switch state unset($next_token); // consume the token break; case 'COLSPAN': $span_mode = 'COL'; $parse_state = 8; // switch state unset($next_token); // consume the token break; case 'ROWSPAN': $span_mode = 'ROW'; $parse_state = 8; // switch state unset($next_token); // consume the token break; case 'CELL': case 'HEADER': case 'ROW': case 'COLUMN': case 'FOOTER': case 'FAIL': $parse_state = $parse_cell_return; // switch state and reparse the token break; default: return wikiplugin_dbreport_parse_error($token, "Invalid keyword '$token->content' in 'CELL'. Field, String, Style or Link expected."); } break; default: return wikiplugin_dbreport_parse_error($token, "Unexpected " . $token->type_name() . " '$token->content' after 'CELL'."); } break; case 8: // SPAN content switch($token->type) { case 'key': // try to parse the keyword as as number $span = (int) $token->content; if ((string) $span == $token->content) { if ($span_mode=='ROW') { $parse_cell->rowspan = $span; } else { $parse_cell->colspan = $span; } unset($next_token); // consume the token } $parse_state = 7; // switch state (and possibly reparse the token) break; default: $parse_state = 7; // switch state and reparse the token } break; case 9: // Text content switch($token->type) { case 'sty': unset($parse_text->style); $parse_text->style = new WikipluginDBReportStyle($token); unset($next_token); // consume the token break; case 'key': switch(TikiLib::strtoupper($token->content)) { case '<': unset($parse_link); $parse_link = new WikipluginDBReportLink($token); // create the link object $parse_text->link =& $parse_link; $parse_link_return = $parse_state; // return to this state $parse_state = 5; // switch state unset($next_token); // consume the token break; default: $parse_state = $parse_text_return; // return to the previous state break; } break; default: $parse_state = $parse_text_return; // return to the previous state break; } break; case 10: // Fail content switch($token->type) { case 'eof': $parse_state = 0; // switch state and reparse the token break; case 'var': case 'txt': unset($parse_text); $parse_text = new WikipluginDBReportText($token); $parse_object->contents[] =& $parse_text; $parse_text_return = $parse_state; // return to this state $parse_state = 9; // switch state unset($next_token); // consume the token break; case 'sty': unset($parse_object->style); $parse_object->style = new WikipluginDBReportStyle($token); unset($next_token); // consume the token break; case 'key': switch(TikiLib::strtoupper($token->content)) { case '<': unset($parse_link); $parse_link = new WikipluginDBReportLink($token); // create the link object $parse_object->link =& $parse_link; $parse_link_return = $parse_state; // return to this state $parse_state = 5; // switch state unset($next_token); // consume the token break; default: unset($parse_object); // we are finished parsing the fail $parse_state = 0; // switch state and reparse the token break; } break; default: return wikiplugin_dbreport_parse_error($token, "Unexpected " . $token->type_name() . " '$token->content' after 'FAIL'."); } break; default: $parse_state = 0; } $token = $next_token; } } } function wikiplugin_dbreport_error_box($error) { $return = '~np~<table style="border-width:1px; border-style:dashed; border-color:red; background:#FFE0E0;"><tr><td>'; switch(gettype($error)) { case 'array': foreach ($error as $entry) { $return .= $entry.'<br/>'; } break; case 'string': case 'object': $return .= (string) $error; break; default: $return .= gettype($error).' ERROR!'; } $return .= '</td></tr></table>~/np~'; return $return; } function wikiplugin_dbreport_message_box($msg) { $return = '<table style="border-width:1px; border-style:dashed; border-color:silver; background:#E0E0FF;"><tr><td>'; switch(gettype($error)) { case 'array': foreach ($msg as $entry) { $return .= $entry.'<br/>'; } break; default: $return .= (string) $msg; } $return .= '</td></tr></table>'; return $return; } function wikiplugin_dbreport_help() { return tra("Run a database report").":<br />~np~{DBREPORT(dsn=>dsnname | db=>dbname, wiki=0|1, debug=>0|1)}".tra("report definition")."{DBREPORT}~/np~"; } function wikiplugin_dbreport_info() { return array( 'name' => tra('DB Report'), 'documentation' => 'PluginDBReport', 'description' => tra('Query an ADOdb database and display results (does not work with PDO)'), 'prefs' => array('wikiplugin_dbreport'), 'body' => tra('report definition'), 'validate' => 'all', 'iconname' => 'table', 'introduced' => 3, 'params' => array( 'dsn' => array( 'required' => false, 'name' => tra('Full DSN'), 'description' => tr('A full DSN (Data Source Name) connection string. Example: ') . '<code>mysql://user:pass@server/database</code>', 'since' => '3.0', 'default' => '', 'filter' => 'url', ), 'db' => array( 'required' => false, 'name' => tra('Wiki DSN Name'), 'description' => tra('The name of a DSN connection defined by the Wiki administrator.'), 'since' => '3.0', 'default' => '', 'filter' => 'text', ), 'wiki' => array( 'required' => false, 'name' => tra('Wiki Syntax'), 'description' => tra('Parse wiki syntax within the report (not parsed by default)'), 'since' => '3.0', 'default' => '', 'filter' => 'digits', 'options' => array( array('text' => '', 'value' => ''), array('text' => tra('Yes'), 'value' => 1), array('text' => tra('No'), 'value' => 0) ), ), 'debug' => array( 'required' => false, 'name' => tra('Debug'), 'description' => tra('Display the parsed report definition (not displayed by default)'), 'since' => '3.0', 'default' => '', 'filter' => 'digits', 'options' => array( array('text' => '', 'value' => ''), array('text' => tra('Yes'), 'value' => 1), array('text' => tra('No'), 'value' => 0) ), ), ), ); } function wikiplugin_dbreport($data, $params) { // TikiWiki globals global $tikilib, $user, $group, $page, $prefs; global $wikiplugin_dbreport_errors, $wikiplugin_dbreport_fields; // wikiplugin_dbreport globals global $wikiplugin_dbreport_errors; global $wikiplugin_dbreport_fields; global $wikiplugin_dbreport_fields_allowed; global $wikiplugin_dbreport_record; // initialize globals $wikiplugin_dbreport_errors = array(); $wikiplugin_dbreport_fields = array(); $wikiplugin_dbreport_fields_allowed = false; $wikiplugin_dbreport_record = null; // extract parameters extract($params, EXTR_SKIP); // we need a dsn or db parameter if (!isset($dsn) && !isset($db)) { return tra('Missing db or dsn parameter'); } // parse the report definition $parse_fix = ($_REQUEST['preview']) && ($prefs['tiki_release']=='2.2'); if ($parse_fix) { $report =& wikiplugin_dbreport_parse($data); } else { $report =& wikiplugin_dbreport_parse(html_entity_decode($data)); } // were there errors? if ($wikiplugin_dbreport_errors) { $ret .= wikiplugin_dbreport_error_box($wikiplugin_dbreport_errors); return $ret; } // create the bind variables array $bindvars = array(); if (isset($report->params)) { foreach ($report->params as $param) { if (isset($param->name)) { $bindvars[$param->name] = $param->text(); } else { $bindvars[] = $param->text(); } } } // translate db name into dsn if (isset($db)) { $perms = Perms::get(array( 'type' => 'dsn', 'object' => $db )); if ( ! $perms->dsn_query ) { return tra('You do not have permission to use this feature'); } // retrieve the dsn string $dsn = $tikilib->get_dsn_by_name($db); } // open the database if (isset($dsn)) { // Force autoloading if (! class_exists('ADOConnection')) { return tr('AdoDb not found'); } $ado = ADONewConnection($dsn); if (!$ado) { $ret .= wikiplugin_dbreport_error_box($ado->ErrorMsg()); return $ret; } else { // execute sql query $ado->SetFetchMode(ADODB_FETCH_NUM); $query =& $ado->Execute($report->sql, $bindvars); $field_count = $query->FieldCount(); $fetchfield = 'FetchField'; if (!$query) { $ret .= wikiplugin_dbreport_error_box($ado->ErrorMsg()); return $ret; } } } else { return (tra('No DSN connection string found!')); } // create an array of field names and their index $field_index = array(); // $field_count = $query->FieldCount(); for ($index = 0; $index<$field_count; $index++) { $column =& $query->$fetchfield($index); $field_index[$column->name] = $index; } // go through the parsed fields and assign indexes foreach ($wikiplugin_dbreport_fields as $key => $value) { $parse_field =& $wikiplugin_dbreport_fields[$key]; $index = $field_index[$parse_field->name]; if (isset($index)) { $parse_field->index = $index; } else { // not a valid field. log the message. $ret .= wikiplugin_dbreport_error_box("The Field '$parse_field->name' was not returned by the SQL query."); return $ret; } } // does the report have a table definition? if (!isset($report->table)) { // create a default definition from the data $report->table = new WikipluginDBReportTable(); $style = 'sortable'; $report->table->style = new WikipluginDBReportStyle($style); $header = new WikipluginDBReportLine(); $style = 'heading'; $header->styles[] = new WikipluginDBReportStyle($style); $report->table->headers[] =& $header; $row = new WikipluginDBReportLine(); $style = 'even'; $row->styles[] = new WikipluginDBReportStyle($style); $style = 'odd'; $row->styles[] = new WikipluginDBReportStyle($style); $report->table->rows[] =& $row; // fill in the cells $field_count = $query->FieldCount(); for ($index = 0; $index<$field_count; $index++) { // get the query field $column =& $query->FetchField($index); // create the header cell unset($text); $text = new WikipluginDBReportText(new WikipluginDBReportToken()); $text->append_string($column->name); unset($cell); $cell = new WikipluginDBReportCell(); // $style = 'heading'; // $cell->style = new WikipluginDBReportStyle($style); $cell->contents[] =& $text; $header->cells[] =& $cell; // create the rows cell unset($cell); $cell = new WikipluginDBReportCell(); unset($field); $field = new WikipluginDBReportField($column->name); $field->index = $index; $cell->contents[] =& $field; $row->cells[] =& $cell; } } // are we debugging? if ($debug) { $ret .= wikiplugin_dbreport_message_box("~np~<pre>".htmlspecialchars($report->code())."</pre>~/np~"); } // generate the report if (!$wiki) { $ret .= '~np~'; } if (!$query->EOF) { // get the first row $current_row = $query->FetchRow(); // start the group breaks if (isset($report->groups)) { foreach ($report->groups as $group) { $group->check_break($current_row); $ret .= $group->start_html($current_row); } } // first row is always considered 'after a break' $breaking = true; // go through the rows while ($current_row) { // do we generate a table header? if ($breaking) { $ret .= $report->table->header_row_html($current_row); } // write the table row $ret .= $report->table->record_row_html($current_row); // get the next row if ($query->EOF) { unset($next_row); $breaking = true; } else { $next_row = $query->FetchRow(); $breaking = false; } // check group breaks if (isset($report->groups)) { $break_end = ''; $break_start = ''; foreach ($report->groups as $group) { if (isset($next_row)) { $breaking = ($group->check_break($next_row) || $breaking); } if ($breaking) { $break_end = $group->end_html($current_row) . $break_end; if (isset($next_row)) { $break_start .= $group->start_html($next_row); } } } } if ($breaking) { $ret .= $report->table->footer_row_html($current_row); $ret .= $break_end; $ret .= $break_start; } // move to the next row $current_row = $next_row; } } else { // no records returned. output the fail message if ($report->fail) { $ret .= $report->fail->html(); } } if (!$wiki) { $ret .= '~/np~'; } // close the database connection $query->Close(); $ado->Close(); // return the result return $ret; }