From fa26ecec19ff3a39f5c87ca90513f458708caed3 Mon Sep 17 00:00:00 2001 From: Carsten Rose <carsten.rose@math.uzh.ch> Date: Fri, 5 Feb 2016 08:53:36 +0100 Subject: [PATCH] Report*: initially copied files to QFQ. Report is not running. --- qfq/report/Db.php | 373 +++++++++++++ qfq/report/Define.php | 64 +++ qfq/report/Error.php | 181 +++++++ qfq/report/Link.php | 638 ++++++++++++++++++++++ qfq/report/Log.php | 214 ++++++++ qfq/report/Report.php | 1081 ++++++++++++++++++++++++++++++++++++++ qfq/report/Sendmail.php | 62 +++ qfq/report/Utils.php | 324 ++++++++++++ qfq/report/Variables.php | 159 ++++++ 9 files changed, 3096 insertions(+) create mode 100644 qfq/report/Db.php create mode 100644 qfq/report/Define.php create mode 100644 qfq/report/Error.php create mode 100644 qfq/report/Link.php create mode 100644 qfq/report/Log.php create mode 100644 qfq/report/Report.php create mode 100644 qfq/report/Sendmail.php create mode 100644 qfq/report/Utils.php create mode 100644 qfq/report/Variables.php diff --git a/qfq/report/Db.php b/qfq/report/Db.php new file mode 100644 index 000000000..596b0caff --- /dev/null +++ b/qfq/report/Db.php @@ -0,0 +1,373 @@ +<?php +/*************************************************************** + * Copyright notice + * + * (c) 2010 Glowbase GmbH <support@glowbase.com> + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +namespace qfq; + +//use qfq; + +require_once(__DIR__ . '/Define.php'); +require_once(__DIR__ . '/Error.php'); +require_once(__DIR__ . '/Log.php'); + + +class Db { + + public $t3_typo_db_host = ""; + /** + * @var string + */ + private $lastUsedDB = ""; + /** + * @var array + */ + private $arrDB = array(); + /** + * @var + */ + private $t3_typo_db_username, $t3_typo_db, $t3_typo_db_password; + /** + * @var Log + */ + private $log; + + // Emulate global variable: will be set much earlier in other functions. Will be shown in error messages. + private $fr_error; + + + /** + * Constructor: + * + * @param Log fully created for logging. + * + */ + + public function __construct($log) { + // CR 25.4.11: require_once does not work here. No idea why + require(PATH_typo3conf . 'localconf.php'); + $this->t3_typo_db_host = $typo_db_host; + $this->t3_typo_db_username = $typo_db_username; + $this->t3_typo_db = $typo_db; + $this->t3_typo_db_password = $typo_db_password; + + $this->log = $log; + } + + /** + * Set Array fr_error: setter function to set most recent values, especially fr_erro['row']. + * Will be shown in error messages. + * + * @param array $fr_error uid, pid, row, column_idx, full_level + */ + public function set_fr_error(array $fr_error) { + $this->fr_error = $fr_error; + } + + /** + * doQueryKeys: See doQuery + * Difference: fake Array for $keys + * + * @param string $dbAlias + * @param string $sql + * @param array $result + * @param string string $expect + * @param string $merge + * @return bool + * @throws CodeReportException + * @throws SqlReportException + * @throws SyntaxReportException + */ + public function doQuery($dbAlias, $sql, array &$result, $expect = EXPECT_GE_0, $merge = MERGE_NONE) { + return ($this->doQueryKeys($dbAlias, $sql, $result, $fake, $expect, $merge, MYSQL_ASSOC)); + } + + /** + * doQueryKeys: fires a show, select, insert, update or delete and collects result. + * insert, update and delete will produce a log entry. + * If: $expect==EXPECT_SQL_OR_STRING, '$sql' can be anything which won't be fired if it's not a SQL statement. + * + * @param string $dbAlias Name of Database to be used. + * @param string $sql Select Query + * @param array $result content depends on $sql. + * $sql='insert ...': mysql_last_insert_id will be returned in $result. + * $sql='update ...' or 'delete ----': mysql_affected_rows will be returned in $result. + * $sql='select ...': all selected rows will be returned in $result. + * $result will be formatted like specified in $merge. + * Attention: with EXPECT_1|EXPECT_0_1 '$result' is a one dimensional array, else a two dimensional array. + * @param array $keys + * @param string $expect + * @param string $merge Applies different modes of merging - MERGE_NONE, MERGE_ROW, MERGE_ALL + * @param int $arrayMode + * @return bool true: all ok + * false: a) Number of rows don't match $expect + * b) $expect==EXPECT_SQL_OR_STRING and $sql is not an SQL expression (instead it's a regular string) - this is not bad, just to indicate that there was no query. + * @throws CodeReportException + * @throws SqlReportException + * @throws SyntaxReportException + */ + public function doQueryKeys($dbAlias, $sql, array &$result, array &$keys, $expect = EXPECT_GE_0, $merge = MERGE_NONE, $arrayMode = MYSQL_NUM) { + $result = ""; + $tmp = ""; + $action = ""; + + $this->selectDB($dbAlias); + + if ($this->fr_error["debug_level"] >= DEBUG_SQL) { + // T3 function: debug() +// debug(array('SQL' => $sql)); + } + + // Extract first parameter to check if it is a SQL statement + $tmp = explode(" ", trim($sql), 2); + $action = strtolower($tmp[0]); + switch ($action) { + case "show" : + case "select": + case "insert": + case "update": + case "delete": + break; // SQL Statement: go further + default: + if ($expect == EXPECT_SQL_OR_STRING) { + $result = $sql; + return (FALSE); // nothing bad, just to indicate $sql was not a SQL statement. + } else + throw new SyntaxReportException ("Unexpected SQL Statement: '$action'", "", __FILE__, __LINE__, array("DB:$dbAlias", "SQL:$sql"), $this->fr_error); + } + + // Fire SQL statement + if (!($res = mysql_query($sql))) { + // Escape query if in AJAX mode + $sql = (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') ? addslashes($sql) : $sql; + throw new SqlReportException ("Did not get result for query.", $sql, __FILE__, __LINE__, $this->fr_error); + } + + + switch ($action) { + case "show" : + case "select": + $action = QUERY; // aggregate 'SLELECT' and 'SHOW' and ... + $num_rows = mysql_num_rows($res); + break; + + case "insert": + $num_rows = mysql_affected_rows(); + $result = mysql_insert_id(); + break; + case "update": + case "delete": + $num_rows = mysql_affected_rows(); + $result = $num_rows; + break; + + default: + throw new CodeReportException ("This error should be catched 20 lines above.", __FILE__, __LINE__); // can't be happen, should already be detected earlier. + } + + // Logging + if ($action != QUERY) { + // Not a query: write log and go home. + $this->log->log_sql('db', '', $num_rows, $result, $sql); + return (TRUE); + } else { + // Logging if localconf log_level >=D2 + $this->log->log_do('error', 'D2', '-', $sql); + } + + // Check $expect against real result. + switch ($expect) { + case EXPECT_0: + return ($num_rows == 0); + break; + case EXPECT_1: + if ($num_rows != 1) return (FALSE); + break; + case EXPECT_0_1: + if ($num_rows > 1) return (FALSE); + break; + case EXPECT_GE_0: + break; + case EXPECT_GE_1: + if ($num_rows == 0) return (FALSE); + break; + case EXPECT_SQL_OR_STRING: + break; + default: + throw new CodeReportException ("Unknown 'expect' qualifier: $expect", __FILE__, __LINE__); + break; + } + + // Preparation to fetch all rows + $tmp = ""; + $fieldCount = 0; + + // Fetch all rows: + while ($row = mysql_fetch_array($res, $arrayMode)) { + foreach ($row as $key => $value) { + $row[$key] = stripslashes($value); + } + + switch ($merge) { + case MERGE_NONE: + $tmp[] = $row; + break; + case MERGE_ROW: + $tmp[] = implode($row); + break; + case MERGE_ALL: + $tmp .= implode($row); + break; + default: + throw new CodeReportException ("Unknown 'merge' qualifier: $merge", __FILE__, __LINE__); + break; + } + } + + // Collect 'keys' + if ($merge == MERGE_NONE) { + $keys = array(); + $numberfields = mysql_num_fields($res); + + for ($i = 0; $i < $numberfields; $i++) { + $keys[] = mysql_field_name($res, $i); + } + } + + // adjust Result Array: one or two dimensions. + switch ($expect) { + case EXPECT_0: + break; + case EXPECT_1: + case EXPECT_0_1: + case EXPECT_SQL_OR_STRING: + $result = $tmp[0]; + break; + default: + $result = $tmp; + } + + if ($merge == MERGE_ALL) + $result = $tmp; + + mysql_free_result($res); + + return (TRUE); + } // doQueryKeys() + + /** + * select DB + * + * @param string $dbAlias : Name of the dbname + * + * @return bool TRUE if ok, else exception. + */ + public function selectDB($dbAlias) { + + if (!$dbAlias) + throw new CodeReportException ("Failed: empty dbAlias", __FILE__, __LINE__); + + // If the db is still selected: do nothing. + if ($dbAlias == $this->lastUsedDB) + return true; + + // if the db is already open - just select it. + if (isset($this->arrDB[$dbAlias]['link'])) { + if (!mysql_select_db($this->arrDB[$dbAlias]['db'])) + throw new SqlReportException ("Failed: mysql_select_db($this->arrDB[$dbAlias]['db'])", "", __FILE__, __LINE__, $this->fr_error); + return true; + } + + $this->openDB($dbAlias); + + return true; + } // openDB() + + /** + * Open specified DB + * + * @param string $dbAlias Name of database to be opened + * @throws SqlReportException + */ + public function openDB($dbAlias) { + // TYPO3 globale Variablen +// global $typo_db_host,$typo_db_username,$typo_db,$typo_db_password; +// Du sollst kein global verwenden!! + + if ($dbAlias == T3) { + $host = $this->t3_typo_db_host; + $username = $this->t3_typo_db_username; + $db = $this->t3_typo_db; + $password = $this->t3_typo_db_password; + } else { +// require(PATH_typo3conf.'ext/formreport/ext_localconf.php'); + $host = $GLOBALS['TYPO3_CONF_VARS'][FORMREPORT][$dbAlias]['host']; + $username = $GLOBALS['TYPO3_CONF_VARS'][FORMREPORT][$dbAlias]['username']; + $db = $GLOBALS['TYPO3_CONF_VARS'][FORMREPORT][$dbAlias]['name']; + $password = $GLOBALS['TYPO3_CONF_VARS'][FORMREPORT][$dbAlias]['password']; + + } + + // If 't3' is specified or the custom DB is not fully specified, take credentials from localconf.php +# $host = $host ? $host : $typo_db_host; +# $username = $username ? $username : $typo_db_username; +# $db = $db ? $db : $typo_db; +# $password = $password ? $password : $typo_db_password; + + + // MySQL Connect + if (!($link = mysql_connect($host, $username, $password))) + throw new SqlReportException ("mysql_connect($host, $username)", "", __FILE__, __LINE__, $this->fr_error); + + // Set connection charset + if (!mysql_set_charset('utf8', $link)) + throw new SqlReportException ("mysql_set_charset('utf8', $link)", "", __FILE__, __LINE__, $this->fr_error); + + // MySQL select + if (!mysql_select_db($db, $link)) + throw new SqlReportException ("mysql_select_db($db)", "", __FILE__, __LINE__, $this->fr_error); + + // Remember that this DB has been opened. + $this->arrDB[$dbAlias]['link'] = $link; + $this->arrDB[$dbAlias]['db'] = $db; + + // Remember the new DB as 'last used' + $this->lastUsedDB = $dbAlias; + + } // selectDB() + + /** + * closeAllDB + * + * @return void + */ + public function closeAllDB() { + + foreach ($this->arrDB as $key => $value) { + if ($key != T3) { + mysql_close($value); + $arrDB[$key] = null; + } + } + + } // closeAllDB() +} diff --git a/qfq/report/Define.php b/qfq/report/Define.php new file mode 100644 index 000000000..592315f8c --- /dev/null +++ b/qfq/report/Define.php @@ -0,0 +1,64 @@ +<?php + +define("EXTKEY", "formreport"); +define("FORMREPORT", "formreport"); +define("LENGTH_HASH", 32); + +// dbalias of Extension DB +define("DB", "db"); +define("T3", "t3"); + +// Constants for tx_form_pi1.php +define("FR_FORM", "tx_formreport_form"); +define("FR_FORMELEMENT", "tx_formreport_formelement"); +define("FR_LOCK", "tx_formreport_lock"); + +define("URL_HASH", "S_hash"); +define("URL_RECORD_ID", "N_r"); +define("URL_FORMNAME", "S_form"); +define("URL_FORM", "URL"); + + +// Definitions for doQuery() +define("EXPECT_0", "expect_0"); +define("EXPECT_1", "expect_1"); +define("EXPECT_0_1", "expect_0_1"); +define("EXPECT_GE_0", "expect_ge_0"); +define("EXPECT_GE_1", "expect_ge_1"); +define("EXPECT_SQL_OR_STRING", "expect_sql_or_string"); + +define("MERGE_NONE", "merge_none"); +define("MERGE_ROW", "merge_row"); +define("MERGE_ALL", "merge_all"); + +define("QUERY", "query"); + +// Definitions for sanatize() strip_tags +define("TAGS_NONE", "none"); +define("TAGS_MARKUP", "markup"); +define("TAGS_CUSTOM", "custom"); +define("TAGS_ALL", "all"); + +// Definitions for sanatize() reaction on changed variables by sanatize them +define("TAGS_EXCEPTION", "exception"); +define("TAGS_SANATIZE", "sanatize"); +define("TAGS_IGNORE", "ignore"); + +// define("LIST_MARKUP_TAGS","<br><p><em><strong><code><samp><kbd><var><cite><dfn><abbr><acronym><q>"); +define("LIST_MARKUP_TAGS", "<br><p><em><strong><font><b><u><i><span><div><ol><ul><li><code><samp><kbd><var><cite><dfn><abbr><acronym><q>"); + +define("DEBUG_SQL", "1"); +define("DEBUG_BASIC", "2"); +define("DEBUG_VERBOSE", "3"); +define("DEBUG_EXTREME", "4"); + +// Set default values - overridden by ext_localconf.php +define("LOCK_RECORDS_INTERVAL", "300"); +define("DFLT_UPLOAD_BASE_DIR", "fileadmin"); +define("DFLT_UPLOAD_TMP_DIR", "fileadmin/tempfiles"); +define("DFLT_UPLOAD_TMP_TTL", "300"); + +define("PATH_ICONS", "typo3conf/ext/" . FORMREPORT . "/icons/"); +// Definitions to allow successfull include of ext_localconf. +//define( 'TYPO3_MODE', '1' ); +//define( 'FORMREPORT', '1' ); diff --git a/qfq/report/Error.php b/qfq/report/Error.php new file mode 100644 index 000000000..0dcbe8524 --- /dev/null +++ b/qfq/report/Error.php @@ -0,0 +1,181 @@ +<?php +/*************************************************************** + * Copyright notice + * + * (c) 2010 Glowbase GmbH <support@glowbase.com> + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +namespace qfq; + +//use qfq; + +/** + * syntaxException: Webmaster made a mistake in tt_content record or form definition + * + * @param string $message + * @param string $code + * @param string $file + * @param string $line + * @param string|array $customMessage =array() a) string: "key: value", b) array("key1: value1","key2: value2", ...) - all items will be displayed on an own line in the error message. + */ +class SyntaxReportException extends \Exception { + private $fr_error; + + public function __construct($message, $code, $file, $line, $customMessage = array(), $fr_error = array()) { + parent::__construct($message); + $this->code = $code; + $this->file = $file; + $this->line = $line; + $this->customMessage = $customMessage; + $this->fr_error = $fr_error; + + } + + public function errorMessage() { +// global $BE_USER; TA: Du sollst kein global verwenden!! + // If '$this->customMessage' is a string, convert it to an array. + if ($this->customMessage && !is_array($this->customMessage)) $this->customMessage = array($this->customMessage); + + //error message +// if ($BE_USER->user["uid"]>0) { TA: Du sollst kein global verwenden!! + if ($GLOBALS['BE_USER']->user["uid"] > 0 || $_SESSION[FORMREPORT]['be_user_uid'] > 0) { + $errorMsg = nl2br("<hr />Error: <strong>" . htmlentities($this->getMessage()) . "</strong><br />"); + $errorMsg .= "Formreport statement: <strong>" . htmlentities($this->fr_error["row"]) . "</strong><br />"; + + // Print custom messages. + foreach ($this->customMessage as $value) { + $tmparr = explode(":", $value, 2); + $errorMsg .= $tmparr[0] . ":<strong>" . htmlentities($tmparr[1]) . "</strong><br />"; + } + $errorMsg .= "T3 Page pid: <strong>" . $this->fr_error["pid"] . "</strong><br />"; + $errorMsg .= "ttcontent record uid: <strong>" . $this->fr_error["uid"] . "</strong><br />"; + $errorMsg .= "File: <strong>" . $this->file . "</strong><br />Line: <strong>" . $this->line . "</strong><br />MSG: <strong>" . $this->code . "</strong><br />"; + $errorMsg .= "StackTrace<pre>" . nl2br($this->getTraceAsString()) . "</pre><hr />"; + } else { + $errorMsg = "<hr />Error: <strong>" . htmlentities($this->getMessage()) . "</strong><hr />"; + } + return $errorMsg; + } // errorMessage() +} // class syntaxException + +/** + * sqlException: An SQL-Query returned an unexpected result + * + * @param string $message + * @param string $sql + * @param string $file + * @param string $line + */ +class SqlReportException extends \Exception { + private $fr_error; + + public function __construct($message, $sql, $file, $line, $fr_error = array()) { + parent::__construct($message); + $this->file = $file; + $this->line = $line; + $this->sql = $sql; + $this->fr_error = $fr_error; + } + + public function errorMessage() { +// global $BE_USER; TA: Du sollst kein global verwenden!! + + //error message +// if ($BE_USER->user["uid"]>0) { TA: Du sollst kein global verwenden!! + if ($GLOBALS['BE_USER']->user["uid"] > 0 || $_SESSION[FORMREPORT]['be_user_uid'] > 0) { + $errorMsg = nl2br("<hr />Error: <strong>" . htmlentities($this->getMessage()) . "</strong><br />MySQL: <strong>" . mysql_error() . "</strong><hr />"); + $errorMsg .= "SQL: <strong>" . htmlentities($this->sql) . "</strong><hr />"; + $errorMsg .= "Formreport: <strong>" . $this->fr_error["row"] . "</strong><hr />"; + $errorMsg .= "T3 Page pid: <strong>" . $this->fr_error["pid"] . "</strong><br>"; + $errorMsg .= "ttcontent record uid: <strong>" . $this->fr_error["uid"] . "</strong><br />"; + $errorMsg .= "Line: <strong>" . $this->line . "</strong><br />File: <strong>" . $this->file . "</strong><hr />"; + + $errorMsg .= "StackTrace<pre>" . nl2br($this->getTraceAsString()) . "</pre><hr />"; + } else { + $errorMsg = "<hr />Error: <strong>" . htmlentities($this->getMessage()) . "</strong><hr />"; + } + return $errorMsg; + } // errorMessage() +} // class sqlException + +/** + * codeException: Error in formreport code + * + * @param string $message + * @param string $file + * @param string $line + */ +class CodeReportException extends \Exception { + + protected $file; + protected $line; + + public function __construct($message, $file = "undefined", $line = "undefined") { + parent::__construct($message); + $this->file = $file; + $this->line = $line; + } + + public function errorMessage() { +// global $BE_USER; TA: Du sollst kein global verwenden!! + +// if ($BE_USER->user["uid"]>0) { TA: Du sollst kein global verwenden!! + if ($GLOBALS['BE_USER']->user["uid"] > 0 || $_SESSION[FORMREPORT]['be_user_uid'] > 0) { + $errorMsg = nl2br("<hr />Error: <strong>" . $this->getMessage() . "</strong><br />File: <strong>" . $this->file . "</strong><br />Line: <strong>" . $this->line . "</strong><hr />"); + $errorMsg .= "StackTrace<pre>" . nl2br($this->getTraceAsString()) . "</pre><hr />"; + } else { + $errorMsg = "<hr />Error: <strong>" . $this->getMessage() . "</strong><hr />"; + } + + return $errorMsg; + } // errorMessage() +} // class codeException + + +/** + * userException: Exception on user-level: Session expired, invalid form submission, no authorization, invalid request, etc. + * + * @param string $message + * @param string $file + * @param string $line + */ +class UserReportException extends \Exception { + + protected $file; + protected $line; + + public function __construct($message, $file = "undefined", $line = "undefined") { + parent::__construct($message); + $this->file = $file; + $this->line = $line; + } + + public function errorMessage() { + if ($GLOBALS['BE_USER']->user["uid"] > 0 || $_SESSION[FORMREPORT]['be_user_uid'] > 0) { + $errorMsg = nl2br("<hr />Error: <strong>" . $this->getMessage() . "</strong><br />File: <strong>" . $this->file . "</strong><br />Line: <strong>" . $this->line . "</strong><hr />"); + $errorMsg .= "StackTrace<pre>" . nl2br($this->getTraceAsString()) . "</pre><hr />"; + } else { + $errorMsg = "<hr />Error: <strong>" . $this->getMessage() . "</strong><hr />"; + } + + return $errorMsg; + } // errorMessage() +} // class userException + diff --git a/qfq/report/Link.php b/qfq/report/Link.php new file mode 100644 index 000000000..783a5d111 --- /dev/null +++ b/qfq/report/Link.php @@ -0,0 +1,638 @@ +<?PHP +/*************************************************************** + * Copyright notice + * + * (c) 2010 Glowbase GmbH <support@glowbase.com> + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +namespace qfq; + +//use qfq; + +require_once(__DIR__ . '/Define.php'); +require_once(__DIR__ . '/Utils.php'); + +/* + * u:url + * m:mailto + * p:page + * + * t:text + * a:AltText + * o:ToolTip + * + * r:render + * g:target + * c:class [n|i|e]:<class> + * q:question <text> + * e:encryption 0|1 + * + * E:edit + * N:new + * D:delete + * H:Help + * I:information + * M:Magnifier + * B:bullet + * P:picture [file] + * C:checkbox [name] + * R:right + * h:hash + * f:formname + * i:recordId + * T:tablename + * + * A: A:[u:p:m] + * G: G:[N|..] + */ + +class Link { + + private $mailto = "", $url = "", $image = "", $text = "", $altText = "", $imageTitle = "", $question = "", $target = "", $formName = "", $additionalUrlParams = ""; + private $toolTip = array(), $modeRender = 0, $picturePosition = "l", $modeHash = FALSE, $recordId = -1, $encryption = 1; + private $linkClass = "", $defaultLinkClass = ""; + private $linkClassSelector = array("i" => "internal", "e" => "external"); + private $renderControl, $link = "", $tableName = ""; + + // Simulate global variable: will be set much earlier in other functions. Will be shown in error messages. + private $fr_error; + + private $exceptionBody = ""; + /** + * @var Utils + */ + private $utils; + /** + * @var string + */ + private $pageAlias = ''; + + /** + * __construct + * + * @param string $fullLevel Recent processed level, f.e.: '10.20.sql' + * @param string $sql Recent processed query, f.e.: SELECT p.name FROM person AS p + * @param string $columnValue Definition of link + * @param int $count + * @param int $columnIndex + * @param string $fr_error + * @param string $dbAlias + */ + public function __construct($fullLevel, $sql, $columnValue, $count, $columnIndex, $fr_error, $dbAlias = '') { + $this->exceptionBody = "Level: " . $fullLevel . ".sql = " . $sql . "\nRow: " . $count . " , Column: " . $columnIndex . " , Bad link: " . $columnValue . "\n"; + $this->fr_error = $fr_error; + $this->dbAlias = $dbAlias; + $this->initRenderControl(); + + } // __construct + + /** + * Initializes RenderControl Array + * + * @param void + * @return void + */ + private function initRenderControl() { + + $this->utils = new Utils(); + + /* + * mode: + * 0: no output + * 1: text + * 2: url + * 3: <a href=url>url</a> + * 4: <a href=url>Text</a> + * + * r=render mode, u=url, t:text und/oder bild + * + * [r][u][t] = mode + */ + + $this->renderControl[0][0][0] = 0; + $this->renderControl[0][0][1] = 0; + $this->renderControl[0][1][0] = 3; + $this->renderControl[0][1][1] = 4; + + $this->renderControl[1][0][0] = 0; + $this->renderControl[1][0][1] = 1; + $this->renderControl[1][1][0] = 3; + $this->renderControl[1][1][1] = 4; + + $this->renderControl[2][0][0] = 0; + $this->renderControl[2][0][1] = 0; + $this->renderControl[2][1][0] = 0; + $this->renderControl[2][1][1] = 4; + + $this->renderControl[3][0][0] = 0; + $this->renderControl[3][0][1] = 1; + $this->renderControl[3][1][0] = 2; + $this->renderControl[3][1][1] = 1; + + $this->renderControl[4][0][0] = 0; + $this->renderControl[4][0][1] = 1; + $this->renderControl[4][1][0] = 2; + $this->renderControl[4][1][1] = 2; + + $this->renderControl[5][0][0] = 0; + $this->renderControl[5][0][1] = 0; + $this->renderControl[5][1][0] = 0; + $this->renderControl[5][1][1] = 0; + } // initRenderControl() + + /** + * Build the whole link + * + * @param string $str : Qualifier with params. 'report'-syntax. F.e.: A:u:www.example.com|G:P:home.gif|t:Home" + * @param string $count + * @param string &$hash hash used by the link, and maybe created for the link if count=1 + * + * @return string The complete Link + */ + public function renderLink($str, $count, &$hash) { + + // fill control array +// $this->initRenderControl(); + + // str="u:http://www.example.com|c:i|t:delete" + $parm = explode("|", $str); + + // Parse all parameter, fill variables + foreach ($parm as $item) { + $arr = explode(":", $item, 2); + $this->parseItem($arr[0], $arr[1]); + } + + // if there is no url or mailto definition: ~global.pageId + if (!$this->url && !$this->mailto) $this->url = "?" . $GLOBALS["TSFE"]->id; + + $this->doCssClass(); + + $htmlUrl = $this->doUrl($count, $hash); + $htmlImage = $this->doImage(); + + // One space distance + if ($this->text) $distance = " "; + + // Compose Image & Text + $distance = ' '; + $this->text = ($this->picturePosition == "l") ? $htmlImage . $distance . $this->text : $this->text . $distance . $htmlImage; + + // ToolTip + $extraSpan = array(); + if ($this->toolTip) { + $extraSpan[0] = "<span " . $this->toolTip[0] . ">" . $this->toolTip[1]; + $extraSpan[1] = "</span>"; + } + + // Create 'fake' modes for encrypted 'mailto' + $prefix = ""; + if ($this->mailto) { + $prefix = "1"; + $this->url = "dummy"; + } + // Create 'fake' mode for ajax delete + if ($this->delete) { + $prefix = "2"; + } + // Compose URL + // get Render Mode via Array renderControl + $mode = $prefix . $this->renderControl[$this->modeRender][$this->url ? 1 : 0][$this->text ? 1 : 0]; + // 0-4 URL, plain email + // 10-14 encrypted email + switch ($mode) { + // 0: No Output + case '0': + case '10': + case '20': + $this->link = ""; + break; + + // 1: 'text' + case '1': + $this->link = $extraSpan[0] . $this->text . $extraSpan[1]; + break; + case '11': + $this->link = $extraSpan[0] . $this->encryptMailtoJS($this->mailto, $this->text, $this->linkClass, FALSE) . $extraSpan[1]; + break; + + // 2: 'url' + case '2': + $this->link = $extraSpan[0] . $this->url . $extraSpan[1]; + break; + case '12': + $this->link = $extraSpan[0] . $this->encryptMailtoJS($this->mailto, $this->text, $this->linkClass, FALSE) . $extraSpan[1]; + break; + + // 3: <a href=url>url</a> + case '3': + $this->link = $htmlUrl . $this->url . '</a>' . $this->toolTip[1]; + break; + case '13': + $this->link = $this->encryptMailtoJS($this->mailto, $this->mailto, $this->linkClass, TRUE); + break; + + // 4: <a href=url>Text</a> + case '4': + $this->link = $htmlUrl . $this->text . '</a>' . $this->toolTip[1]; + break; + case '14': + $this->link = $this->encryptMailtoJS($this->mailto, $this->text, $this->linkClass, TRUE); + break; + case '21': + case '22': + case '23': + case '24': + $this->link = "<a href=\"javascript: void(0);\" onClick=\"var del = new FR.Delete({recordId:'" . $count . "',hash:'" . $hash . "',forward:'" . $this->pageAlias . "'});\" " . $this->linkClass . ">" . $this->text . "</a>"; + } + + return $this->link; + + } // buildHash() + + /** + * Parse Item of link string, fill class global variables. + * + * @param string $key : F.e.: 'u' + * @param string $value : F.e.: 'http://www.nzz.ch' + * @throws SyntaxReportException + */ + private function parseItem($key, $value) { + global $TYPO3_CONF_VARS; + + $_EXTKEY = FORMREPORT; + + switch ($key) { + // URL + case "u": + if ($this->url || $this->mailto) throw new SyntaxReportException ("Multiple URL, PAGE or MAILTO defined : '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->url = $value; + $this->defaultLinkClass = $TYPO3_CONF_VARS[$_EXTKEY]['css_class']['external']; + break; + case "m": + if ($this->url || $this->mailto) throw new SyntaxReportException ("Multiple URL, PAGE or MAILTO defined : '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->mailto = $value; + $this->defaultLinkClass = $TYPO3_CONF_VARS[$_EXTKEY]['css_class']['external']; + break; + case "p": + if ($this->url || $this->mailto) throw new SyntaxReportException ("Multiple URL, PAGE or MAILTO defined : '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->pageAlias = $value ? $value : $GLOBALS["TSFE"]->id; // If no pageid|pagealias ist defined, take current page + $this->url = "?" . $this->pageAlias; + $this->defaultLinkClass = $TYPO3_CONF_VARS[$_EXTKEY]['css_class']['internal']; + break; + // Text + case "t": + $this->text = $value; + break; + case "a": + $this->altText = $value; + break; + case "o": + $this->toolTip = $this->utils->createToolTip($value); + break; + + // Image + case "P": + if ($this->image) throw new SyntaxReportException ("Multiple images defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->image = $value; + $this->AltText = "Grafic: " . $value; + $this->imageTitle = $value; + break; + case "B": + if ($this->image) throw new SyntaxReportException ("Multiple images defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->image = PATH_ICONS . "bullet-" . ($value ? $value : "green") . '.gif'; + $this->defaultAltText = "Bullet: " . $value; + $this->imageTitle = $value; + break; + case "C": + if ($this->image) throw new SyntaxReportException ("Multiple images defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->image = PATH_ICONS . "checked-" . ($value ? $value : "green") . '.gif'; + $this->defaultAltText = "Checked: " . $value; + $this->imageTitle = $value; + break; + case "D": + if ($this->image) throw new SyntaxReportException ("Multiple images defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->image = PATH_ICONS . 'delete.gif'; + $this->defaultAltText = "Delete"; + $this->imageTitle = "Delete"; + $this->delete = true; + // Include Extjs library + $this->utils->loadJSlib($this->fr_error); + break; + case "E": + if ($this->image) throw new SyntaxReportException ("Multiple images defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->image = PATH_ICONS . 'edit.gif'; + $this->defaultAltText = "Edit"; + $this->imageTitle = "Edit"; + break; + case "H": + if ($this->image) throw new SyntaxReportException ("Multiple images defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->image = PATH_ICONS . 'help.gif'; + $this->defaultAltText = "Help"; + $this->imageTitle = "Help"; + break; + case "I": + if ($this->image) throw new SyntaxReportException ("Multiple images defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->image = PATH_ICONS . 'info.gif'; + $this->defaultAltText = "Information"; + $this->imageTitle = "Information"; + break; + case "N": + if ($this->image) throw new SyntaxReportException ("Multiple images defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->image = PATH_ICONS . 'new.gif'; + $this->defaultAltText = "New"; + $this->imageTitle = "New"; + break; + case "S": + if ($this->image) throw new SyntaxReportException ("Multiple images defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->image = PATH_ICONS . 'show.gif'; + $this->defaultAltText = "Details"; + $this->imageTitle = "Details"; + break; + + // Misc + case "r": + if ($this->modeRender) throw new SyntaxReportException ("Multiple render modes defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->modeRender = $value; + break; + case "g": + if ($this->target) throw new SyntaxReportException ("Multiple 'target' defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->target = $value; + break; + case "c": + if ($this->linkClass) throw new SyntaxReportException ("Multiple linkClass defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->linkClass = $value; + break; + case "q": + if ($this->question) throw new SyntaxReportException ("Multiple question defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->question = $value ? $value : "Please confirm"; + break; + case "e": + if ($this->encryption != 1) throw new SyntaxReportException ("Multiple encryption defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->encryption = $value ? $value : "1"; + break; + case "h": + if ($this->modeHash) throw new SyntaxReportException ("Multiple modeHash defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->modeHash = TRUE; + break; + case "f": + if ($this->formName) throw new SyntaxReportException ("Multiple formName defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->formName = $value; + break; + case "U": //if($this->additionalUrlParams) throw new syntaxException ( "Multiple additionalUrlParams defined: '$key'","",__FILE__,__LINE__, "Column: " . $fthis->r_error["columnIndex"], $this->fr_error); + //$this->additionalUrlParams = $value; + + // Save url params as array! + $param = explode('=', $value); + $this->additionalUrlParams[$param[0]] = $param[1]; + break; + case "i": + if ($this->recordId != -1) throw new SyntaxReportException ("Multiple recordId defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->recordId = $value; + break; + case "R": + if ($this->picturePosition != "l") throw new SyntaxReportException ("Multiple picturePosition defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->picturePosition = "r"; + break; + case "T": + if ($this->tableName) throw new SyntaxReportException ("Multiple tableName defined: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + $this->tableName = $value; + break; + + // A,G + case "G": + case "A": + $arr = explode(":", $value, 2); + $this->parseItem($arr[0], $arr[1]); + break; + case "" : + break; + default: + throw new SyntaxReportException ("Unknown link qualifier: '$key'", "", __FILE__, __LINE__, "Column: " . $this->fr_error["columnIndex"], $this->fr_error); + + } + + } // splitAndAddDelimter() + + /** + * Parse CSS Class Settings + * + * @param void + * + * @return void + */ + private function doCssClass() { + + // class: i|e|n|<custom name> + if ($this->linkClass != 'n') { + if (!$this->linkClass) $this->linkClass = $this->defaultLinkClass; + + if ($this->linkClassSelector[$this->linkClass]) + $this->linkClass = $this->linkClassSelector[$this->linkClass]; + + $this->linkClass = ' class="' . $this->linkClass . '"'; + } else { + $this->linkClass = ""; + } + } // encryptMailtoJS() + + /** + * Build URL + * + * @param int $count Row count of current query. $count=1 means 'generate new hash values', everything else means 'take existing hash values'. + * @param string $hash RC for hash if count=1, else 'hash' to use. + * @return string + */ + private function doUrl($count, &$hash) { + // build URL + $htmlUrl = ""; + + // If there is no encryption: handle the mailto as an ordinary URL + if ($this->mailto && $this->encryption == 0) { + $this->url = "mailto:" . $this->mailto; + $this->mailto = ""; + } + + if ($this->url) { + $param = array(); + + if ($this->modeHash) { + $param[] = $this->buildHash($count, $hash); + } else { + if ($this->formName) $param[] = URL_FORMNAME . '=' . $this->formName; + if ($this->recordId != -1) $param[] = URL_RECORD_ID . '=' . $this->recordId; + if ($this->additionalUrlParam) $param[] = $this->additionalUrlParams; + } + + if ($param) { + // Append '&' or '?' depending if there is already a '?' + $this->url .= (strpos($this->url, '?') >= 0) ? '&' : '?'; + // Append all additional params. + $this->url .= implode('&', $param); + } + + // target + if ($this->target) $this->target = ' target="' . $this->target . '"'; + + // question + if ($this->question) $this->question = ' onclick="return confirm(\'' . $this->question . '\')"'; + + $htmlUrl = '<a href="' . $this->url . '"' . $this->linkClass . $this->target . $this->question . $this->toolTip[0] . '>'; + } + return ($htmlUrl); + } // doCssClass() + + /** + * Build the URL and/or Hash + * + * @return string The complete Link + */ + private function buildHash($count, &$hash) { + + if ($count == 1) { + $hash = $this->utils->randomAlphaNumUnique(); + + $_SESSION[FORMREPORT][$hash]['formName'][0] = $this->formName; + $_SESSION[FORMREPORT][$hash]['referrer'] = $_SERVER['REQUEST_URI']; + // Delete Links: tablename mandatory + if ($this->tableName) { + $_SESSION[FORMREPORT][$hash]['tableName'] = $this->tableName; + $_SESSION[FORMREPORT][$hash]['dbAlias'] = $this->dbAlias; + } + } + + $_SESSION[FORMREPORT][$hash]['idMap'][$count]['recordId'] = $this->recordId; + $_SESSION[FORMREPORT][$hash]['idMap'][$count]['param'] = $this->additionalUrlParams; + + return (URL_HASH . '=' . $hash . '&' . URL_RECORD_ID . '=' . $count); + } // doUrl() + + /** + * Create Image HTML Tag + * @return string $htmlImage + * @internal param $void + * + */ + private function doImage() { + $htmlImage = ""; + + // Build Image + if ($this->image) { + + if ($this->altText) $this->altText = ' alttext="' . $this->altText . '"'; + + if ($this->image) $this->image = ' src="' . $this->image . '"'; + + if ($this->imageTitle) $this->imageTitle = ' title="' . $this->imageTitle . '"'; + + $htmlImage = '<img' . $this->image . $this->altText . $this->imageTitle . ' />'; + } + + return ($htmlImage); + } // doImage() + + /** + * Encrypt the mailto address via JS. + * Email address protected against email crawler (as long as they don't interpret JS). + * + * <script language=javascript><!-- + * var mm1 = name + * var mm2 = @domain. + * var ... = tld + * document.write("<a href=" + "mail" + "to:" + mm1 + mm2 + ... + ">" + name + "</a>") + * document.write("<a href=" + "mail" + "to:" + mm1 + mm2 + ... + ">" + @domain. + "</a>") + * document.write("<a href=" + "mail" + "to:" + mm1 + mm2 + ... + ">" + tld + "</a>") + * //--></script>'; + * + * @param string $mailto Email address to encrypt. + * @param string $text Text to wrap <a href..>, </a> around. + * @param string $class Optional class definition + * @param bool $href TRUE: create a '<a>', FALSE: just encrypt or show the email, no link. + * + * @return string The complete Link + */ + private function encryptMailtoJS($mailto, $text, $class = "", $href = TRUE) { + + // Prepare CSS Definition + if ($class) $class = str_replace('"', "'", $class); + + // Split $mailto + $tmp = $this->splitAndAddDelimter($mailto, "@"); + $arr = array_merge($this->splitAndAddDelimter($tmp[0], "."), $this->splitAndAddDelimter($tmp[1], ".")); + + $tt = "<script language=javascript><!--" . chr(10); + $ii = 0; + if ($href) { + $dw = 'document.write("<a href=" + "mail" + "to:"'; + foreach ($arr as $value) { + // Setup JS Variables + $tt .= 'var mm' . $ii . '= "' . $value . '"' . chr(10); + // Compose $dw (documentwrite statement) + $dw .= ' + mm' . $ii++; + } + $dw .= ' + "' . $class . str_replace('"', '\\"', $this->toolTip[0]) . '>"'; + $closeDw = '"</a>")'; + } else { + $dw = 'document.write('; + $closeDw = ')'; + } + + // Wrap mailto around text + if ($mailto == $text) { + // Text is an email: wrap every single part of mailto. + $ii = 0; + foreach ($arr as $value) { + $tt .= $dw . " + mm" . $ii++ . ' + ' . $closeDw . chr(10); + } + } else { + // Single wrap text + $tt .= $dw . ' + "' . $text . '" + ' . $closeDw . chr(10); + } + + $tt .= '//--></script>'; + if ($href) $tt .= $this->toolTip[1]; + + return ($tt); + } //renderLink() + + /** + * Split a string around the $delimiter. + * + * Append the delimiter to each part except the last one. + * + * @param $mailto + * @param $delimiter + * @return array + */ + private function splitAndAddDelimter($mailto, $delimiter) { + $value = ''; + + $arr = explode($delimiter, $mailto); // split string + + foreach ($arr as $key => $value) { + $arr[$key] = $value . $delimiter; + } + + if (isset($key)) + $arr[$key] = $value; + + return ($arr); + } // parseItem +} \ No newline at end of file diff --git a/qfq/report/Log.php b/qfq/report/Log.php new file mode 100644 index 000000000..8d2e28224 --- /dev/null +++ b/qfq/report/Log.php @@ -0,0 +1,214 @@ +<?php +/*************************************************************** + * Copyright notice + * + * (c) 2010 Glowbase GmbH <support@glowbase.com> + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +/* + * Howto + * + * 1) Specify Logfiles (incl. path) in ext_localconf.php in $TYPO3_CONF_VARS[$_EXTKEY]['log'][<name>]. + * <name> means a class of 'error', 'mail', 'sql', 'browser', ... + * 2) Call 'log_do($class, $status, $origin, $message)' to write one entry. + * Every entry will start with: [<status>|<origin>|<date/time>|<IP>|<fe.uid>|<fe.username>|<URL>]. + * Specify $message string or $message array. + * 3) For 'sql' and 'mail' log entries, use the wrapper log_sql() or log_mail(). + */ + +namespace qfq; + +//use qfq; + +class Log { + /** + * @var array + */ + private $config; // filled in __construct, Definition: tx_fr_variables->collectGlobalVariables + + /** + * @var array order to compare loglevel + */ + private $config_level = array('E' => 0, 'W' => 1, 'I' => 2, 'D1' => 3, 'D2' => 4, 'D3' => 5); + + /** + * @var array Emulate global variable: will be set much earlier in other functions. Will be shown in error messages. + */ + private $fr_error = array(); + + /** + * Initializes class + * + * @param array $tmp_config : Part of array 'fr_array': 'global.' + * + * @throws \Exception + */ + public function __construct(array $tmp_config) { + global $TYPO3_CONF_VARS; + $this->prepare_log_file_dir($TYPO3_CONF_VARS[EXTKEY]['log']['sql']); + $this->prepare_log_file_dir($TYPO3_CONF_VARS[EXTKEY]['log']['mail']); + $this->prepare_log_file_dir($TYPO3_CONF_VARS[EXTKEY]['log']['error']); + $this->prepare_log_file_dir($TYPO3_CONF_VARS[EXTKEY]['log']['browser']); + + $this->config = $tmp_config; + + } // __construct() + + /** + * Check if path of logfile exists. No: create it. + * Check if path of logfile is writeable. + * + * @param string $filename Name of logfile + * @throws \Exception + */ + private function prepare_log_file_dir($filename) { + $this->logFile = $filename; + + // extract optional path component + $path = dirname($filename); + + // If there is a path: check if directories really exist and are writeable. + if ($path) { + if (file_exists($path)) { + // Directory already exists: check if it is writeable. + if (!is_writable($path)) throw new \Exception ("Failed: directory '$path' of Logfile '$filename' is not writeable."); + } else { + // Directoy doesn't exist: create it. + if (!mkdir($path, 0775, true)) + throw new \Exception ("Failed to create directory '$path' for Logfile '$filename'"); + } + } + } + + /** + * Set Array fr_error: setter function to set most recent values. + * Will be shown in log messages. + * + * @param array $fr_error : uid, pid, row, column_idx, full_level + * + * @return void + */ + public function set_fr_error(array $fr_error) { + $this->fr_error = $fr_error; + } // prepare_log_file_dir() + + /** + * log_sql: wrapper for log_do() for sql logging + * + * @param string $origin : Sender of the logmessage. F.e.: 'form', 'save', 'report', 'extjs', ... + * @param string $msg : Only filled if there was an error + * @param int $affected_rows : Number of rows inserted, updated or deleted. + * @param int $new_id : last_insert_id() + * @param string $sql : SQL statement fired + * + * @return void + */ + public function log_sql($origin, $msg, $affected_rows, $new_id, $sql) { + + if ($msg) { + $status = 'E'; + } else { + $status = 'I'; + $msg = 'OK'; + } + + $text = "[$msg]"; + $text .= "[$affected_rows]"; + $text .= "[$new_id]"; + $text .= "[$sql]"; + + $this->log_do('sql', $status, $origin, $text); + } // log_do() + + /** + * log_do: format log entries, build fix part, append dynamic part, write. + * + * @param string $class : 'error', 'mail', 'sql', 'browser'. New classes has to be defined in ext_localconf.php + * @param string $status : 'E' (0:error), 'W' (1:warning), 'I' (2:information), 'D1' (3:debug verbose), 'D2' (4:debug very verbose), 'D3' (5:debug very very verbose) + * @param string $orign : Sender of the logmessage. F.e.: 'form', 'save', 'report', 'extjs', ... + * @param string /array $message: skalar or one dimensal array with logmessage(s). + * @throws CodeReportException + * @throws SyntaxReportException + */ + public function log_do($class, $status, $origin, $message) { + global $TYPO3_CONF_VARS; + $tmp = ''; + + // Check if loglevel should be respected and if 'yes' if loglevel is greater than this message: break + if (($class == 'error' || $class == 'browser') && $this->config_level[$status] > $TYPO3_CONF_VARS[EXTKEY]['log']['level']) + return; + + // Get filename + $filename = $TYPO3_CONF_VARS[EXTKEY]['log'][$class]; + if (!$filename) + throw new SyntaxReportException ("Missing logfile definition: Undefind TYPO3_CONF_VARS[" . EXTKEY . "]['log']['$class']", "", __FILE__, __LINE__); + + if ($this->fr_error['pid']) $tmp = '|' . $this->fr_error['pid']; + if ($this->fr_error['uid']) $tmp .= '|' . $this->fr_error['uid']; + if ($this->fr_error['full_level']) $tmp .= '|' . $this->fr_error['full_level']; + + // F.e.: [I|Form|2012.01.31-19:59:33|IP|fe.uid|fe.username|URL] + $text = '[' . $status . '|' . $origin . '|' . date('Y.m.d-H:i:s') . '|' . $this->config["REMOTE_ADDR"] . '|' . $this->config["fe_user_uid"] . '|' . $this->config["fe_user"] . $tmp . '|' . $this->config["url"] . ']'; + + // If 'message' is an array, wrap every element (but not the last) with '[', ']'. + if ($message && is_array($message)) { + $last = array_pop($message); + if ($last && $message) { + $text .= '[' . implode('][', $message) . ']'; + } + $message = $last; + } + $text .= $message; + + // Write whole entry + $this->log_write($filename, $text); + } // log_sql() + + /** + * Logs every email (failed or successfull) + * + * @param string $orign : Sender of the logmessage. F.e.: 'form', 'save', 'report', 'extjs', ... + * @param string $status : 'E' (0:error), 'W' (1:warning), 'I' (2:information), 'D1' (3:debug verbose), 'D2' (4:debug very verbose), 'D3' (5:debug very very verbose) + * @param string $msg : Message + * @param array $mailarr : Details of the mail + * + * $mailarr['sender'] Absender + * $mailarr['receiver'] Empfaenger, mehrere mit Komma getrennt + * $mailarr['subject'] Betreff + * $mailarr['body'] Mailinhalt + * $mailarr['src'] level oder form_element.id um herauszufinden wer die Mail gesendet hat + * + * @param string $mailarr : data to log + * @return The content that is displayed on the website + */ + + public function log_mail($origin, $status, $msg, $mailarr) { + + $text = '[' . $msg . "]"; + $text .= '[' . $mailarr["sender"] . ']'; + $text .= '[' . $mailarr["receiver"] . ']'; + $text .= '[' . $mailarr["subject"] . ']'; + $text .= '[' . $mailarr["body"] . ']'; + + $this->log_do('mail', $status, $origin, $text); + + } // log_mail() + +} diff --git a/qfq/report/Report.php b/qfq/report/Report.php new file mode 100644 index 000000000..2986fd4fe --- /dev/null +++ b/qfq/report/Report.php @@ -0,0 +1,1081 @@ +<?php +/*************************************************************** + * Copyright notice + * + * (c) 2010 Glowbase GmbH <support@glowbase.com> + * All rights reserved + * + ***************************************************************/ + +namespace qfq; + +//use qfq; + + +require_once(__DIR__ . '/Define.php'); +require_once(__DIR__ . '/Utils.php'); +require_once(__DIR__ . '/Variables.php'); +require_once(__DIR__ . '/Error.php'); +require_once(__DIR__ . '/Db.php'); +require_once(__DIR__ . '/Link.php'); +require_once(__DIR__ . '/Sendmail.php'); + + +class cObj { + public $data = array(); +} + +/** + * Plugin 'FormReport' for the 'formreport' extension. + * + * @author Glowbase GmbH <support@glowbase.com> + * @package TYPO3 + * @subpackage tx_formreport + */ +class Report { +// var $prefixId = 'tx_formreport_pi1'; // Same as class name +// var $scriptRelPath = 'pi1/class.tx_formreport_pi1.php'; // Path to this script relative to the extension dir. +// var $pi_checkCHash = true; + + /** + * @var string + */ + private $dbAlias = ''; + /** + * @var Log + */ + private $log = null; + + // frArray[10.50.5.sql][select ...] + private $frArray = array(); + // $indexArray[10][50][5] one entry per 'sql' statement + private $indexArray = array(); + // TODO to explain +// private $resultArray = array(); + private $levelCount = 0; + //private $counter = 0; + /** + * @var Variables + */ + private $variables = null; +// private $saveFile; + //class with util functions + /** + * @var Utils + */ + private $utils = null; + + //TODO: wo wird die initialisiert? Im Original suchen. + /** + * @var Db + */ + private $db = null; + /** + * @var Sendmail + */ + private $sendmail = null; + + private $page_control = array(); + + // Emulate global variable: will be set much earlier in other functions. Will be shown in error messages. + private $fr_error = array('uid' => '', 'pid' => '', 'row' => '', 'debug_level' => '0', 'full_level' => ''); + + //TODO:here: FAKE. Known inside Typo3 and should be transfered to Report somehow + private $cObj; + + /** + * __construct + * + */ + public function __construct() { + + //TODO: Fake + $this->cObj = new cObj(); + $this->cObj->data['uid'] = 1; + + $this->page_control["msgbox"]["pagec"] = "Please confirm!"; + + $this->page_control["hash"]["paged"] = "h"; + $this->page_control["hash"]["pagee"] = "h"; + $this->page_control["hash"]["pagen"] = "h"; + + $this->page_control["icon"]["paged"] = "D"; + $this->page_control["icon"]["pagee"] = "E"; + $this->page_control["icon"]["pageh"] = "H"; + $this->page_control["icon"]["pagei"] = "I"; + $this->page_control["icon"]["pagen"] = "N"; + $this->page_control["icon"]["pages"] = "S"; + + } // __construct + + /** + * @param $content + * @param $conf + * @return string Rendered code of the queries + * @throws userException + */ + public function process($bodytext) { + + try { + $this->utils = new Utils(); + + $this->variables = new Variables($this->cObj->data["uid"]); + + // Sanitize function for POST and GET Parameters. + // Merged URL-Parameter (key1, id etc...) in resultArray. + $this->variables->resultArray = array_merge($this->variables->resultArray, array("url." => $this->utils->sanitize()), array("global." => $this->variables->collectGlobalVariables())); + + // Set static values, which won't change during this run. +// $this->fr_error["pid"] = $this->variables->resultArray['global.']['page_id']; + $this->fr_error["pid"] = $this->variables->get('resultArray', 'global.', 'page_id'); + $this->fr_error["uid"] = $this->cObj->data["uid"]; + $this->fr_error["debug_level"] = 0; + + // Create Logclass. +// $this->log = new Log($this->variables->resultArray['global.']); + $this->log = new Log($this->variables->get('resultArray', 'global.')); + + // Create DB Class. Take care to prepare a fr_log instance. + $this->db = new Db($this->log); + + // Create sendmail Class. Take care to prepare a fr_log instance. + $this->sendmail = new Sendmail($this->log); + + // Setter function to emulate global variables. + $this->db->set_fr_error($this->fr_error); + $this->log->set_fr_error($this->fr_error); + + // Iteration over Bodytext + $ttLineArray = explode("\n", $bodytext); + + foreach ($ttLineArray as $index => $line) { + // Fill $frArray, $indexArray, $resultArray + $this->parseFRLine($line); + } + // Sort array + $this->sortIndexArray($this->indexArray, $this->generateSortArg()); + + // Report + $content = $this->triggerReport(); + +// } catch ( codeException $e ) { +// $content = $e->errorMessage(); +// } catch ( syntaxException $e ) { +// $content = $e->errorMessage(); +// } catch ( sqlException $e ) { +// $content = $e->errorMessage(); + } catch (\Exception $e) { + $content = $e->getMessage(); + } + + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { +// debug($this->frArray); +// debug($_SESSION); + } + + return $content; + } // main() + + /** + * Split line in level, command, content and fill 'frArray', 'levelCount', 'indexArray' + * Example: 10.50.5.sql = select * from person + * + * @param string $ttLine : line to split in level, command, content + * @return void + */ + private function parseFRLine($ttLine) { + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'parseFRLine')); + } + + + // 10.50.5.sql = select ... + $arr = explode("=", trim($ttLine), 2); + + // 10.50.5.sql + $key = strtolower(trim($arr[0])); + + // comment ? + if (substr($key, 0, 1) == "#") return; + + // select ... + $value = trim($arr[1]); + + // 10.50.5.sql + $arrKey = explode('.', $key); + + // frCmd = "sql" + $frCmd = $arrKey[count($arrKey) - 1]; + + // remove last item (cmd) + unset($arrKey[count($arrKey) - 1]); + + // save elements only if there is a level specified + if (count($arrKey)) { + // level = "10.50.5" + $level = implode(".", $arrKey); + + // fill Array + $this->setLine($level, $frCmd, $value); + } + } // form2hash() + + + private function setLine($level, $frCmd, $value) { + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'setLine')); + } + + // store complete line reformatted in frArray + $this->frArray[$level . "." . $frCmd] = $value; + + // per sql command + //pro sql cmd wir der Indexarray abgefüllt. Dieser wird später verwendet um auf den $frArray zuzugreifen + //if(preg_match("/^sql/i", $frCmd) == 1){ + if ($frCmd == "sql" || $frCmd == "form") { + // Remember max level + $this->levelCount = max(substr_count($level, '.') + 1, $this->levelCount); + // $indexArray[10][50][5] + $this->indexArray[] = explode(".", $level); + } + } // triggerReport() + + /** + * Sorts the associative array. + * + * @param Array $ary : The unsorted Level Array + * @param String $clause : the sort argument 0 ASC, 1 ASC... according to the number of columns + * @return The content that is displayed on the website + */ + private function sortIndexArray(&$ary, $clause, $ascending = true) { + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'sortIndexArray')); + } + + $clause = str_ireplace('order by', '', $clause); + $clause = preg_replace('/\s+/', ' ', $clause); + $keys = explode(',', $clause); + $dirMap = array('desc' => 1, 'asc' => -1); + $def = $ascending ? -1 : 1; + + $keyAry = array(); + $dirAry = array(); + foreach ($keys as $key) { + $key = explode(' ', trim($key)); + $keyAry[] = trim($key[0]); + if (isset($key[1])) { + $dir = strtolower(trim($key[1])); + $dirAry[] = $dirMap[$dir] ? $dirMap[$dir] : $def; + } else { + $dirAry[] = $def; + } + } + $fnBody = ''; + for ($i = count($keyAry) - 1; $i >= 0; $i--) { + $k = $keyAry[$i]; + $t = $dirAry[$i]; + $f = -1 * $t; + $aStr = '$a[\'' . $k . '\']'; + $bStr = '$b[\'' . $k . '\']'; + + if (strpos($k, '(') !== false) { + $aStr = '$a->' . $k; + $bStr = '$b->' . $k; + } + + if ($fnBody == '') { + $fnBody .= "if({$aStr} == {$bStr}) { return 0; }\n"; + $fnBody .= "return ({$aStr} < {$bStr}) ? {$t} : {$f};\n"; + } else { + $fnBody = "if({$aStr} == {$bStr}) {\n" . $fnBody; + $fnBody .= "}\n"; + $fnBody .= "return ({$aStr} < {$bStr}) ? {$t} : {$f};\n"; + } + } + + if ($fnBody) { + $sortFn = create_function('$a,$b', $fnBody); + usort($ary, $sortFn); + } + } // collectRow() + + + private function generateSortArg() { + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'generateSortArg')); + } + + $sortArg = ""; + + for ($i = 0; $i < $this->levelCount; $i++) { + $sortArg = $sortArg . $i . " ASC, "; + } + $sortArg = substr($sortArg, 0, strlen($sortArg) - 2); + return $sortArg; + } // composeLinkPart() + + /** + * Executes the queries recursive. This Method is called for each Sublevel. + * + * ROOTLEVEL + * This method is called once from the main method. + * For the first call the method executes the rootlevels + * + * SUBLEVEL + * For each rootlevel the method calls it self whith the levelmode 0 + * If the next Level is a Sublevel it will be executed and $this->counter will be added by 1 + * The sublevel calls the method again for a following sublevel + * + * @param int $cur_level Which level it will call [10] = level 1, [10.10] = level 2 ... + * @param string $super_level_array The Value-Array of the indexarray [0=>10, 1=>50]* @param int $counter The outer numeric Arraykey of indexarray + * @return string The content that is displayed on the website + * @throws codeException + * @throws SqlReportException + * @throws SyntaxReportException + * @throws UserReportException + */ + private function triggerReport($cur_level = 1, $super_level_array = "", $counter = 0) { + + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'triggerReport')); + } + + $lineDebug = 0; + $content = ""; + $rowTotal = 0; + + // CurrentLevel "10.10.50" + $full_level = implode(".", $this->indexArray[$counter]); + // Superlevel "10.10" + $full_super_level = implode(".", $super_level_array); + + //condition1: indexArray + //condition2: full_level == Superlevel (but at the length of the Superlevel) + while ($counter < count($this->indexArray) && $full_super_level == substr($full_level, 0, strlen($full_super_level))) { + + //True: The cur_level is a subquery -> continue + if ($cur_level != count($this->indexArray[$counter])) { + $full_level = implode(".", $this->indexArray[++$counter]); + continue; + } + + // Set dbAlias if one is specified. Else keep the parent one. + $this->dbAlias = $this->getValueParentDefault("db", $full_super_level, $full_level, $cur_level, DB); + + // Set debug, if one is specified else keep the parent one. + $lineDebug = $this->getValueParentDefault("debug", $full_super_level, $full_level, $cur_level, 0); + $this->fr_error["debug_level"] = max($lineDebug, $this->fr_error["debug_level"]); // collect the biggest debuglevel >> debug $_SESSION at the end. + + // Prepare Error reporting + $this->fr_error["row"] = $full_level . ".sql = " . $this->frArray[$full_level . ".sql"]; + $this->fr_error["full_level"] = $full_level . ".sql"; + + // Setter function to emulate global variables + $this->db->set_fr_error($this->fr_error); + $this->log->set_fr_error($this->fr_error); + + // Debug + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('full_level' => $full_level)); + } + + // Do form ? + if (isset($this->frArray[$full_level . "." . "form"])) { + // Disable Typo3 Cache for this page to avoid problems with the session array / ajax + //TODO: Is this still necessary? +// $GLOBALS["TSFE"]->set_no_cache(); + + // Trigger 10.form, 20.form... + // Use the form passed by URL via hash + if ($this->frArray[$full_level . "." . "form"] == URL_FORM) { + $hash = $this->variables->resultArray["url."][URL_HASH]; + $formName = $_SESSION[FORMREPORT][$hash]['formName'][0]; + } else { + // Use the form configured in tt_content + // Replace possible variables for formRecordId + $formRecordId = isset($this->frArray[$full_level . ".formrecordid"]) ? $this->variables->doVariables($this->frArray[$full_level . ".formrecordid"]) : 0; + $formName = $this->frArray[$full_level . ".form"]; + + // Fill $_SESSION + // If a hash has already been set by url, use that one, otherwise generate a new hash array + if (isset($this->variables->resultArray["url."][URL_HASH])) { + $hash = $this->variables->resultArray["url."][URL_HASH]; + + // Store all allowed forms in an array + $allowedForms = array(); + + // If there are already forms in the hash array, keep them + if (is_array($_SESSION[FORMREPORT][$hash]['formName'])) { + $allowedForms = $_SESSION[FORMREPORT][$hash]['formName']; + } + array_push($allowedForms, $formName); + + $_SESSION[FORMREPORT][$hash]['formName'] = $allowedForms; + + } else { + // Otherwise configure new session array + $hash = $this->form2hash($formName, $formRecordId); + } + } + + $full_level = implode(".", $this->indexArray[++$counter]); + continue; + } // Do form + + // Prepare SQL: replace variables. + $sql = $this->variables->doVariables($this->frArray[$full_level . ".sql"]); + + // DEBUG + if ($this->fr_error["debug_level"] >= DEBUG_SQL) { + // T3 function: debug() +// debug(array("native" => $full_level . ".sql = " . $this->frArray[$full_level . ".sql"], "replaced" => $full_level . ".sql = " . $sql)); + } + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug($this->variables->resultArray); + } + + //Execute SQL. All errors have been already catched. + unset($result); + $this->db->doQueryKeys($this->dbAlias, $sql, $result, $keys, EXPECT_GE_0, MERGE_NONE, MYSQL_NUM); + + // If an array is returned, $sql was a query, otherwise an 'insert', 'update', 'delete', ... + // Query: total nummber of rows + // insert: last_insert_id + // delete, update: number of affected rows + $rowTotal = is_array($result) ? count($result) : $result; + + $this->variables->resultArray[$full_level . ".line."]["total"] = $rowTotal; + + // HEAD: If there is at least one record, do 'head'. + if ($rowTotal > 0) + $content .= $this->variables->doVariables($this->frArray[$full_level . "." . "head"]); + + // Prepare row alteration + $arrRbgd = explode("|", $this->frArray[$full_level . "." . "rbgd"]); + + //--------------------------------- + // Process each row of resultset + $columnValueSeperator = ""; + $rowIndex = 0; + foreach ($result as $row) { + // record number counter + $this->variables->resultArray[$full_level . ".line."]["count"] = ++$rowIndex; + + // replace ~count and ~total in result, if the variables specify their own full_level. This can't be replaced before firing the query. + for ($ii = 0; $ii < count($row); $ii++) { + $row[$ii] = str_replace("~" . $full_level . ".line.count", $rowIndex, $row[$ii]); + $row[$ii] = str_replace("~" . $full_level . ".line.total", $rowTotal, $row[$ii]); + } + + // Create Assoc Array of result + unset($rowAssoc); + for ($i = 0; $i < count($row); $i++) { + $rowAssoc[$keys[$i]] = $row[$i]; + } + + //Fills the Results in the resultArray to substitute variables +// array wird neu einzeln gefuellt $this->tx_fr_variables_pi1->resultArray[$full_level . "."] = $rowAssoc; + + // SEP set seperator (empty on first run) + $content .= $columnValueSeperator; + $columnValueSeperator = $this->variables->doVariables($this->frArray[$full_level . "." . "sep"]); + + // RBGD: gerade- ungerade- Zeilen/Rows + $content .= str_replace("rbgd", $arrRbgd[$rowIndex % 2], $this->frArray[$full_level . "." . "rbeg"]); + + //----------------------------- + // COLUMNS: Collect all columns + $content .= $this->collectRow($row, $keys, $full_level, $rowIndex); + + // REND + $content .= $this->variables->doVariables($this->frArray[$full_level . "." . "rend"]); + + // Trigger subqueries of this level + $content .= $this->triggerReport($cur_level + 1, $this->indexArray[$counter], $counter + 1); + + // RENR + $content .= $this->variables->doVariables($this->frArray[$full_level . "." . "renr"]); + + // this is necessary: queries 2,3,.. should not be replaced with content of resultArray but with the most recent values. So delete the entry in resultArray. + unset($this->variables->resultArray[$full_level . ".line."]["total"]); + unset($this->variables->resultArray[$full_level . ".line."]["count"]); + } + + // set last valid counts again: should be available for later queries + $this->variables->resultArray[$full_level . ".line."]["total"] = $rowTotal; + $this->variables->resultArray[$full_level . ".line."]["count"] = $rowIndex; + + //Print althead or tail + if ($rowTotal > 0) { + $content .= $this->variables->doVariables($this->frArray[$full_level . "." . "tail"]); + } else { + $content .= $this->variables->doVariables($this->frArray[$full_level . "." . "althead"]); + } + + $full_level = implode(".", $this->indexArray[++$counter]); + } + + return $content; + } // doPage() + + /** + * Determine value: + * 1) if one specified in line: take it + * 2) if one specified in upper level: take it + * 3) if none above take default + * Set value on $full_level + * + * @param string $level_key - 'db' or 'debug' + * @param string $full_super_level - f.e.: 10.10. + * @param string $full_level - f.e.: 10.10.10. + * @param string $cur_level - f.e.: 2 + * @param string $default - f.e.: 0 + * @return string The calculated value. + */ + private function getValueParentDefault($level_key, $full_super_level, $full_level, $cur_level, $default) { + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'getValueParentDefault')); + } + + if ($this->frArray[$full_level . "." . $level_key]) { + $value = $this->frArray[$full_level . "." . $level_key]; + } else { + if ($cur_level == 1) { + $value = $default; + } else { + $value = $this->variables->resultArray[$full_super_level . ".line."][$level_key]; + } + } + $this->variables->resultArray[$full_level . ".line."][$level_key] = $value; + + return ($value); + } // doFixColPosPage() + + /** + * Prepare Session Array with Hash Entry: Only for form + * + * @param $formName + * @param $formRecordId + * @return string + */ + private function form2hash($formName, $formRecordId) { + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'form2hash')); + } + $hash = $this->utils->randomAlphaNumUnique(); + + $_SESSION[FORMREPORT][$hash]['formName'][0] = $formName; + $_SESSION[FORMREPORT][$hash]['referrer'] = $_SERVER['REQUEST_URI']; + + if (is_numeric($formRecordId) && $formRecordId >= 0) { + $_SESSION[FORMREPORT][$hash]['idMap'][1]['recordId'] = $formRecordId; + $_SESSION[FORMREPORT][$hash]['idMap'][1]['param'] = ""; + } + + return ($hash); + } // renderColumn() + + /** + * Steps through 'row' and collects all columns + * + * @param array $row Recent row fetch from sql resultset. + * @param array $keys List of all columnnames + * @param string $full_level Recent position to work on. + * @param string $rowIndex Index of recent row in resultset. + * @return string Collected content of all printable columns + * @throws SyntaxReportException + */ + private function collectRow(array $row, array $keys, $full_level, $rowIndex) { + $content = ""; + + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'collectRow')); + } + + for ($ii = 0; $ii < count($keys); $ii++) { + + $this->fr_error["columnIndex"] = $ii; // Debugging Information + // Setter Function to emulate global variables. + $this->db->set_fr_error($this->fr_error); + $this->log->set_fr_error($this->fr_error); + + $tmp = $this->renderColumn($ii, $keys[$ii], $row[$ii], $full_level, $rowIndex, $show); + if ($show) { + //prints + $content .= $this->variables->doVariables($this->frArray[$full_level . "." . "fbeg"]); + $content .= $tmp; + $content .= $this->variables->doVariables($this->frArray[$full_level . "." . "fend"]); + } + } + return ($content); + } // getValueParentDefault() + + + /** + * The main method of the PlugIn + * + * @param string $content : The PlugIn content + * @param array $conf : The PlugIn configuration + * @return string The content that is displayed on the website + */ + //Liefert für ~1.1.name -> [1.1][name] zurück + /** + * Renders column depending of column name (if name is a reserved column name) + * + * @param string $columnIndex : column index of recent row + * @param string $columnName : columnname + * @param string $columnValue : content of column + * @param string $full_level : position to be processed + * @param string $rowIndex : index of row of resultset to be processed + * @param bool $show : RC: 'TRUE' content will be printed on screen + * + * @return string rendered column + * + */ + private function renderColumn($columnIndex, $columnName, $columnValue, $full_level, $rowIndex, &$show) { + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'renderColumn')); + } +#debug(array('columnIndex'=>$columnIndex, 'columnName'=>$columnName, 'columnValue'=>$columnValue,'full_level'=>$full_level,"rowIndex"=>$rowIndex)); + $show = TRUE; + if (substr($columnName, 0, 1) == "_") { + $show = FALSE; + $columnName = substr($columnName, 1); + } + + $content = ""; + switch ($columnName) { + case "link": + $link = new Link($full_level, $this->frArray[$full_level . ".sql"], $columnValue, $rowIndex, $columnIndex, $this->fr_error); + $content .= $link->renderLink($columnValue, $rowIndex, $this->frArray[$full_level . "." . "hash." . "$columnIndex"]); +# unset $link; + break; + case "exec": + $content .= $this->myExec($columnValue); + break; + + case "Page": + case "Pagec": + case "Paged": + case "Pagee": + case "Pageh": + case "Pagei": + case "Pagen": + case "Pages": + $linkValue = $this->doFixColPosPage($columnName, $columnValue); + + $link = new Link($full_level, $this->frArray[$full_level . ".sql"], $linkValue, $rowIndex, $columnIndex, $this->fr_error, $this->dbAlias); + $content .= $link->renderLink($linkValue, $rowIndex, $this->frArray[$full_level . "." . "hash." . "$columnIndex"]); + break; + + case "page": + case "pagec": + case "paged": + case "pagee": + case "pageh": + case "pagei": + case "pagen": + case "pages": +#debug($columnValue); + $linkValue = $this->doPage($columnName, $columnValue); +// debug($linkValue); + + $link = new Link($full_level, $this->frArray[$full_level . ".sql"], $linkValue, $rowIndex, $columnIndex, $this->fr_error, $this->dbAlias); + $content .= $link->renderLink($linkValue, $rowIndex, $this->frArray[$full_level . "." . "hash." . "$columnIndex"]); + break; + + case "img": + // "<path to image>|[alttext]|[text behind]" renders to: <img src="<path to image>" alt="[alttext]">[text behind] + if (empty($columnValue)) break; + $tmp = explode("|", $columnValue, 3); + if ($tmp[0] == "") break; + $content .= '<img src="' . $tmp[0] . '" alt="' . $tmp[1] . '">' . $tmp[2]; + break; + + case "mailto": + // "<email address>|[Real Name]" renders to (encrypted via JS): <a href="mailto://<email address>"><email address></a> OR <a href="mailto://<email address>">[Real Name]</a> + $tmp = explode("|", $columnValue, 2); + if ($tmp[0] == "") break; + + $t1 = explode("@", $tmp[0], 2); + $content .= "<script language=javascript><!--" . chr(10); + if (empty($tmp[1])) $tmp[1] = $tmp[0]; + + $content .= 'var contact = "' . substr($tmp[1], 0, 2) . '"' . chr(10); + $content .= 'var contact1 = "' . substr($tmp[1], 2) . '"' . chr(10); + $content .= 'var email = "' . $t1[0] . '"' . chr(10); + $content .= 'var emailHost = "' . $t1[1] . '"' . chr(10); + + $content .= 'document.write("<a href=" + "mail" + "to:" + email + "@" + emailHost+ ">" + contact + "</a>")' . chr(10); + $content .= 'document.write("<a href=" + "mail" + "to:" + email + "@" + emailHost+ ">" + contact1 + "</a>")' . chr(10); + $content .= '//--></script>'; + break; + + case "sendmail": + // 'Absender|Empfaenger, mehrere mit Komma getrennt|Betreff|Mailinhalt' + $tmp = explode("|", $columnValue, 4); + + $mail['receiver'] = $tmp[0]; + $mail['sender'] = $tmp[1]; + $mail['subject'] = $tmp[2]; + $mail['body'] = $tmp[3]; + + $content = $this->sendmail->sendmail($mail); + break; + + case "vertical": + // '<Text>|[angle]|[width]|[height]|[tag]' , width and heigth needs a unit (px, em ,...), 'tag' might be 'div', 'span', ... + $arr = explode("|", $columnValue, 5); + + # angle + $angle = $arr[1] ? $arr[1] : 270; + + # width + $width = $arr[2] ? $arr[2] : "1em"; + $tmp = "width:$width; "; + + # height + if ($arr[3]) + $tmp .= "height:" . $arr[3] . "; "; + + # tag + if ($arr[4]) { + $tag = explode(" ", trim($arr[4]), 2); + $tag_open = "<" . $arr[4] . " "; + $tag_close = "</" . $tag[0] . ">"; + } else { + $tag_open = "<div "; + $tag_close = "</div>"; + } + + # http://scottgale.com/blog/css-vertical-text/2010/03/01/ + #$style = "writing-mode:tb-rl; -webkit-transform:rotate(270deg); -moz-transform:rotate(270deg); -o-transform: rotate(270deg); white-space:nowrap; width:1em; display: block;"; + $style = "width:1em; filter: flipv fliph; transform: rotate(" . $angle . "deg) translate(-10em,0); transform-origin: 0 0; writing-mode:tb-rl; -webkit-transform:rotate(" . $angle . "deg); -moz-transform:rotate(" . $angle . "deg); -o-transform: rotate(" . $angle . "deg); white-space:nowrap; display: block;"; + + #$style = "line-height: 1.5em; background:#eee; display: block; white-space: nowrap; padding-left: 3px; writing-mode: tb-rl; filter: flipv fliph; transform: rotate(270deg) translate(-10em,0); transform-origin: 0 0; -moz-transform: rotate(270deg) translate(-10em,0); -moz-transform-origin: 0 0; -webkit-transform: rotate(270deg) translate(-10em,0); -webkit-transform-origin: 0 0;"; + $content = $tag_open . 'style="' . $style . '">' . $arr[0] . $tag_close; + + + break; + + case "F": + $newColumnName = ""; + $newFinalColumnName = ""; + $remain = array(); + $striptags = FALSE; + $tag = ""; + + # 'Q:mailto|Z|V:mail_first|support@example.com' + $arr = explode("|", $columnValue); + foreach ($arr as $value) { + $kv = explode(":", $value); + switch ($kv[0]) { + case "Q": + $newColumnName = $kv[1]; + #if(!$newColumnName) throw new syntaxException ( "Missing a 'reserved column name' for parameter 'Q' in column 'F': $columnValue","",__FILE__,__LINE__,$this->fr_error); + if ($newColumnName == 'F') throw new SyntaxReportException ("Not allowed: 'F' as 'reserved column name' for parameter 'Q': $columnValue", "", __FILE__, __LINE__, $this->fr_error); + break; + case "Z": + $show = FALSE; + break; + case "T": + $striptags = TRUE; + break; + case "X": + $tag = $kv[1]; + if (!$tag) throw new SyntaxReportException ("Missing the 'tag' parameter for 'X'): $columnValue", "", __FILE__, __LINE__, $this->fr_error); + break; + case "V": + $newFinalColumnName = $kv[1]; + if (!$newFinalColumnName) throw new SyntaxReportException ("Missing the 'name' parameter for 'V': $columnValue", "", __FILE__, __LINE__, $this->fr_error); + break; + case 'F': + throw new SyntaxReportException ("Qualifier 'F' is not allowed inside of a column with column name 'F': $columnValue", "", __FILE__, __LINE__, $this->fr_error); + break; + # Save every non 'F' qualifier for later usage + default: + $remain[] = $value; + break; + } + } + # Check for needed action + # if(!$newColumnName) throw new syntaxException ( "Missing parameter 'Q' in column 'F': $columnValue","",__FILE__,__LINE__,$this->fr_error); + if ($newColumnName) + $columnName = $newColumnName; + else + $columnName = "no column name defined"; + + # reconstruct remaining parameters + $arr = implode("|", $remain); + # render + $content = $this->renderColumn($columnIndex, $columnName, $arr, $full_level, $rowIndex, $dummy); + + if ($newFinalColumnName) + $columnName = $newFinalColumnName; + + # striptags + if ($striptags) $content = strip_tags($content); + # tag + if ($tag) { + $arr = explode(" ", $tag); + $content = "<" . $tag . ">" . $content . "</" . $arr[0] . ">"; + } + break; + + default : + $content .= $columnValue; + break; + } + $this->variables->resultArray[$full_level . "."][$columnName] = $content; + + return $content; + } // getResultArrayIndex() + + /** + * The main method of the PlugIn + * + * @param string $content : The PlugIn content + * @param array $conf : The PlugIn configuration + * @return string The content that is displayed on the website + */ + //Checkt ob der Beginn von Array2 gleich ist wie Array1 + // gibt true/false zurück + /** + * Executes the Command in $cmd + * RC: if RC==0 Returns Output, else 'RC - Output' + * + * @param string $cmd : contains the Comand + * @return string The content that is displayed on the website + */ + private function myExec($cmd) { + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'myExec')); + } + + exec($cmd, $arr, $rc); + + $output = implode('<BR>', $arr); + if ($rc != 0) + $output = $rc . " - " . $output; + + return ($output); + } // compareArraystart() + + /** + * The main method of the PlugIn + * + * @param string $content : The PlugIn content + * @param array $conf : The PlugIn configuration + * @return string The content that is displayed on the website + */ + //Check ob arr1 nur 1 Feld mehr hat als arr2 + /** + * Renders PageX: convert position content to token content. Respect default values depending on PageX + * + * @param string $columnName + * @param string $columnValue + * @return string rendered link + * + * $columnValue: + * ------------- + * [<page id|alias>[¶m=value&...]] | [record id] | [text] | [tooltip] | [msgbox] | [class] | [target] | [render mode] | [create hash] + * + * param[0]: <page id|alias>[¶m=value&.. + * param[1]: record id + * param[2]: text + * param[3]: tooltip + * param[4]: msgbox + * param[5]: class + * param[6]: target + * param[7]: render mode + * param[8]: create hash + * @throws SyntaxReportException + */ + private function doFixColPosPage($columnName, $columnValue) { + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'doFixColPosPage')); + } + + $link = ""; + + // Split definition + $param = explode('|', $columnValue); + if (count($param) > 9) throw new SyntaxReportException ("Too many parameter (max=9): $columnValue", "", __FILE__, __LINE__, $this->fr_error); + + // make first 'P' lowercase + $columnName = 'p' . substr($columnName, 1); + + // -- Page -- + // Split PageId|PageAlias and URL Params + $tmparr = explode('&', $param[0], 2); + + $link .= $this->composeLinkPart('p', $tmparr[0]); // -- PageID -- + $link .= $this->composeLinkPart('U', $tmparr[1]); // -- URL Params -- + $link .= $this->composeLinkPart('i', $param[1]); // -- record id -- + $link .= $this->composeLinkPart('t', $param[2]); // -- Text -- + $link .= $this->composeLinkPart('o', $param[3]); // -- tooltip -- + $link .= $this->composeLinkPart('q', $param[4], $this->page_control["msgbox"][$columnName]); // -- msgbox + $link .= $this->composeLinkPart('c', $param[5]); // -- class -- + $link .= $this->composeLinkPart('g', $param[6]); // -- target -- + $link .= $this->composeLinkPart('r', $param[7]); // -- render mode -- + + if (!$param[8]) $param[8] = $this->page_control["hash"][$columnName]; // if no hash behaviour defined, use default + if ($param[8] == "h") $link .= "h|"; + + if ($this->page_control["icon"][$columnName]) $link .= $this->page_control["icon"][$columnName] . "|"; + + return ($link); + } // compareArraylength() + + /** + * If there is a value (or a defaultValue): compose it together with qualifier and delimiter. + * + * @param string $qualifier + * @param string $value + * @param string $defaultValue + * + * @return string rendered link + */ + private function composeLinkPart($qualifier, $value, $defaultValue = "") { + + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'composeLinkPart')); + } + + if (!$value) $value = $defaultValue; + + if ($value) + return ($qualifier . ":" . $value . "|"); + + return ''; + } // parseFRLine() + + /** + * Store level, frCmd, value + * + * @param string $level : 10.50.5 + * @param string $frCmd : sql + * @param string $value : select ... + * @return void + */ + //Füllt frArray und indexArray + /** + * Renders pageX: extract token and determine if any default value has be applied + * + * @param string $columnName + * @param string $columnValue + * + * @return string rendered link + */ + private function doPage($columnName, $columnValue) { + $defaultQuestion = ''; + + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'doPage')); + + } + $param = explode('|', $columnValue); + + # get all defaultvalues, depending on the columnname + $defaultImage = $this->page_control["icon"][$columnName]; + $defaultHash = $this->page_control["hash"][$columnName]; + # define defaultquestion only, if pagetype needs a question + if ($this->page_control["msgbox"][$columnName]) $defaultQuestion = 'q:' . $this->page_control["msgbox"][$columnName]; + + foreach ($param as $key) { + switch (substr($key, 0, 1)) { + case 'P': + case 'E': + case 'N': + case 'D': + case 'H': + case 'I': + case 'S': + case 'B': + case 'C': + $defaultImage = ''; // if any of the img token is given: no default + break; + case 'h': + $defaultHash = ''; // if a hash definition is given: no default + break; + case 'q': + $defaultQuestion = ''; // if a question is given: no default + break; + } + } + + $columnValue .= "|"; + + // append defaulst + if ($defaultImage) $columnValue .= $defaultImage . "|"; + if ($defaultHash) $columnValue .= $defaultHash . "|"; + if ($defaultQuestion) $columnValue .= $defaultQuestion . "|"; + +#debug($columnValue); + + return ($columnValue); + } // setLine() + + /** + * Generate SortArgument + * + * @param void + * @return string: sortArg + */ + //Hier wird das Sortierargument generiert + + private function getResultArrayIndex($variable) { + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'getResultArrayIndex')); + } + + $variable = substr($variable, 1, strlen($variable)); + return "[" . preg_replace_callback("/[a-z]/", "replaceToIndex", $variable) . "][" . preg_replace_callback("/[^a-z]/", "replaceToIndex", $variable) . "]"; + + } // generateSortArg() + + + private function compareArraystart($arr1, $arr2) { + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'compareArraystart')); + } + + for ($i = 0; $i < count($arr1); $i++) { + if ($arr1[$i] != $arr2[$i]) { + return false; + } + } + return true; + } // sortIndexArray() + + + private function compareArraylength($arr1, $arr2) { + if ($this->fr_error["debug_level"] >= DEBUG_EXTREME) { + // T3 function: debug() +// debug(array('function' => 'compareArraylength')); + } + + if (count($arr1) + 1 == count($arr2)) { + return true; + } + return false; + } // myExec() + +} // tx_formreport_pi1 diff --git a/qfq/report/Sendmail.php b/qfq/report/Sendmail.php new file mode 100644 index 000000000..1bc9d23e4 --- /dev/null +++ b/qfq/report/Sendmail.php @@ -0,0 +1,62 @@ +<?php + +namespace qfq; + +//use qfq; + +require_once(__DIR__ . '/Define.php'); +require_once(__DIR__ . '/Error.php'); + + +class Sendmail { + + /** + * @var Log + */ + private $Log; + + /** + * Constructor: + * + * @param Log $fr_log + * @internal param Log $class : fully created for logging. + * + */ + + public function __construct(Log $fr_log) { + + $this->Log = $fr_log; + } + + /** + * Send an email. Mail delivery should work - else the mails might disappear + * Seperate lines in the body with '\r\n' + * RC: if RC==0 Returns Output, else 'RC - Output' + * + * @param array $mailarr : $mailarr['receiver'] (multiple with comma), $mailarr['sender'], $mailarr['subject'], $mailarr['body'] + * @return string + */ + + public function sendmail($mailarr) { + $status = 'E'; + + // sending only if there is a receiver ! + if ($mailarr['receiver']) { + // if(mail($receiver,$subject,$message, "From: ".$sender."\nX-Mailer: PHP/ . $phpversion()", "-f ".$sender)) + if (mail($mailarr['receiver'], $mailarr['subject'], $mailarr['body'], "X-Mailer: PHP/" . phpversion() . "\r\nFrom: " . $mailarr['sender'] . ".\r\n", "-f " . $mailarr['sender'])) { + $msg = "Mail has been sent"; + $status = 'I'; + } else { + $msg = "Sending Mail not accepted"; + } + } else { + $msg = "Mail not sent: missing receiver"; + } + + // Log every mail + $this->Log->log_mail("form", $status, $msg, $mailarr); + + return ($msg); + } // sendmail() + +} diff --git a/qfq/report/Utils.php b/qfq/report/Utils.php new file mode 100644 index 000000000..accf74cde --- /dev/null +++ b/qfq/report/Utils.php @@ -0,0 +1,324 @@ +<?php +/*************************************************************** + * Copyright notice + * + * (c) 2010 Glowbase GmbH <support@glowbase.com> + * All rights reserved + * + ***************************************************************/ + +namespace qfq; + +//use qfq; + +require_once(__DIR__ . '/Define.php'); +require_once(__DIR__ . '/Db.php'); + + +class Utils { + /** + * @var Db + */ + private $db = null; + + /** + * @param $db + */ + public function __construct($db = null) { + //TODO: Im Original nachschauen woher die globale Variable $Db kommt??? Ubergangsweise hier im Konstruktor plaziert. Wird aber aktuell nicht initialisiert!!! + $this->db = null; + } + + /** + * Sanitize GET and POST Parameters. Categorize Parameter: name begins with: + * 'S_' String: sanitize via t3lib_db::quoteStr, htmltospecialchars + * 'H_' HTML: no sanitize at all + * [Typo3, xdebug, zend debugger] special - no change + * [rest] has to be numeric - if not, will not be copied. + * + * @return Array of sanitized GET and POST Variables. Only correctly filled variables will be returned. + */ + public function sanitize() { + $arr = array(); + // Merge GET and POST arrays. GET will be preferred. + $params = array_merge($_POST, $_GET); + + foreach ($params as $key => $value) { + + // if $value is an array (e.g. when using checkboxes on a 'set' field), convert it to a csv list. + if (is_array($value)) { + $value = implode(",", $value); + } + + switch (substr($key, 0, 2)) { + //alphanum + // String values. HTML entitites will be converted, strings escaped. + case "S_": +// $arr[$key] = mysql_real_escape_string(htmlspecialchars($value)); +// TA: htmlspecialchars darf hier nicht angewendet werden - Daten sollen so in DB geschrieben werden wie sie angegeben werden + $arr[$key] = mysql_real_escape_string($value); + break; + //default (F_ kommt vom ursprünglichen namen form) + //Tags werden bis auf die Whitelist LIST_MARKUP_TAGS (siehe define) ersetzt + case "F_": + $arr[$key] = addslashes(strip_tags($value, LIST_MARKUP_TAGS)); + break; + //email + //ExtJs definition (unterstützt nicht alle erlaubten Emailadressen) + case "E_": + $pattern = "/^((\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,6})?$/"; + if (preg_match($pattern, $value) > 0) { + $arr[$key] = $value; + } + break; + //url + //Protokoll http / https muss angegeben werden. Definition ExtJs + case "U_": + $pattern = "/((((^https?)|(^ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?))?$/i"; + if (preg_match($pattern, $value) > 0) { + $arr[$key] = $value; + } + break; + //html + // HTML allowed: no sanitize at all. + case "H_": + $arr[$key] = addslashes($value); + break; + //date + //DD.MM.YYYY or DD/MM/YYYY + case "D_": +// $pattern = "/^\d\d[(.|\/)]\d\d[(.|\/)]\d\d\d\d$/"; +// if(preg_match($pattern, $value)>0){ +// $arr[$key] = $value; +// } + + // use strtotime instead of a complex regex: + // - the function accepts different formats of times / dates (e.g. speaking names) - this is extremely powerful + // - the date is automatically converted to a defined format, which makes it easier to process in later steps + if (strtotime($value)) { + $arr[$key] = date("Y-m-d", strtotime($value)); + } + break; + //time + //hh:mm:ss + case "T_": + //$pattern = "/^(((0|1)\d|2[0-4])[:]([0-6]\d)[:]([0-6]\d))?$/"; // CR: restriction to 00-23 is to strong +// $pattern = "/^\d?\d[:]\d?\d[:]?\d?\d?$/"; +// if(preg_match($pattern, $value)>0){ +// $arr[$key] = $value; +// } + + // use strtotime instead of a complex regex: + // - the function accepts different formats of times / dates (e.g. speaking names) - this is extremely powerful + // - the date is automatically converted to a defined format, which makes it easier to process in later steps + if (strtotime($value)) { + $arr[$key] = date("h:i:s", strtotime($value)); + } + break; + //date_time + //DD.MM.YYYY hh:mm:ss + case "Z_": + //$pattern = "/^((0[1-9]|[12][0-9]|3[01])[.](0[1-9]|1[012])[.](19|20)\d\d[ ]((0|1)\d|2[0-4])[:]([0-6]\d)[:]([0-6]\d))?$/"; +// $pattern = "/^(\d*\d[.]\d*\d[.]\d*\d*\d*\d[ ]\d?\d[:]\d?\d[:]?\d?\d?$/"; +// if(preg_match($pattern, $value)>0){ +// $arr[$key] = $value; +// } + + // use strtotime instead of a complex regex: + // - the function accepts different formats of times / dates (e.g. speaking names) - this is extremely powerful + // - the date is automatically converted to a defined format, which makes it easier to process in later steps + if (strtotime($value)) { + $arr[$key] = date("Y-m-d h:i:s", strtotime($value)); + } + + break; + case "N_": + //num + //Only numeric-value allowed + $pattern = "/^-?[0-9]*$/"; + if (preg_match($pattern, $value) > 0) { + $arr[$key] = $value; + } + break; + default: + /* 'id' (T3 page identifier) and ZEND 'debugger' GET_VARS won't be sanitized*/ + ; + switch ($key) { + case 'id': + case 'start_debug': + case 'debug_host': + case 'send_sess_end': + case 'debug_session_id': + case 'original_url': + case 'debug_start_session': + case 'debug_no_cache': + case 'debug_port': + $arr[$key] = $value; + continue 2; + } + break; + } + } + return ($arr); + } // sanitize() + + /** + * Create a new _unique_ (max 20 tries, else breaks) hash string and saves it in $_SESSION[FORMREPORT][$hash] + * + * @return string A random alphanumeric hash, or + * FALSE if it was not possible to create a unique hash. + */ + public function randomAlphaNumUnique() { + + for ($i = 0; $i < 20; $i++) { + + $hash = $this->randomAlphaNum(LENGTH_HASH); + + if (!isset($_SESSION[FORMREPORT][$hash])) { + $_SESSION[FORMREPORT][$hash] = array(); + return ($hash); + } + } + // Too much tries without success + return (FALSE); + } // randomAlphaNum () + + /** + * @param int $length Length of the required hash string + * @return string A random alphanumeric hash + */ + private function randomAlphaNum($length) { + $possible_characters = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + $string = ""; + while (strlen($string) < $length) { + $string .= substr($possible_characters, rand() % (strlen($possible_characters)), 1); + } + + return ($string); + } // randomAlphaNumUnique() + + /** + * If record locking has been enabled in ext_localconf.php, create a record in the lock table + * + * @param string $form + * @param int $record_id + * @param string $tablename + * @param string $dbalias + * @param $tx_db_pi1 + */ + function setLockRecord($form, $record_id, $tablename, $dbalias, &$tx_db_pi1) { + $result = ''; + $mode = $GLOBALS['TYPO3_CONF_VARS'][FORMREPORT]['lock_records']['mode']; + if ($mode == "warn" || $mode == "lock") { + $query = "INSERT INTO `" . FR_LOCK . "` (`phpsession_id`, `fe_user_uid`, `form`, `record_id`, `tablename`, `dbalias`) VALUES ('" . session_id() . "', '" . $GLOBALS["TSFE"]->fe_user->user["uid"] . "', '" . $form . "', '" . $record_id . "', '" . $tablename . "', '" . $dbalias . "')"; + $this->db->doQuery(DB, $query, $result, EXPECT_0); + } // if + } // eo setLockRecord + + + /** + * If record locking has been enabled in ext_localconf.php, + * delete all expired locking records + * check if a record exists in the lock table for the currently edited record + * + * @param int $form form_id + * @param int $record_id record_id + * @param string $tablename tablename + * @param Db $dbalias Db class object + * @param $tx_db_pi1 + * @return array|bool information on locking mode, locking user and timestamp. false if not locked + */ + function checkLockRecord($form, $record_id, $tablename, $dbalias, &$tx_db_pi1) { + // Get config values from localconf or use default from define.php + $mode = $GLOBALS['TYPO3_CONF_VARS'][FORMREPORT]['lock_records']['mode']; + $interval = ($GLOBALS['TYPO3_CONF_VARS'][FORMREPORT]['lock_records']['interval']) ?: LOCK_RECORDS_INTERVAL; + + if ($mode == "warn" || $mode == "lock") { + // Delete all expired locking records + $query = "DELETE FROM `" . FR_LOCK . "` WHERE timestamp + INTERVAL " . $GLOBALS['TYPO3_CONF_VARS'][FORMREPORT]['lock_records']['interval'] . " SECOND < NOW()"; + $this->db->doQuery(DB, $query, $result, EXPECT_0); + + // Check if locking records exist + $query = "SELECT fe_user_uid, phpsession_id, date_format(timestamp + INTERVAL " . $interval . " SECOND, \"%H:%i %d.%m.%Y\") as lock_endtime FROM `" . FR_LOCK . "` WHERE `record_id`='" . $record_id . "' and `tablename`='" . $tablename . "' and `dbalias`='" . $dbalias . "' LIMIT 1"; + $this->db->doQuery(DB, $query, $result, EXPECT_GE_0); + + // If result is empty, return false + if (empty($result)) + return false; + + // If user is the same as the current one, return false + // Compare fe_user_uid and session-id + if ($result[0]['phpsession_id'] == session_id()) + return false; + + // Build array with locking information - will be used to create a warning/error message etc. + $arr = array(); + $arr['mode'] = $mode; + $arr['fe_user_uid'] = $result[0]['fe_user_uid']; + $arr['lock_endtime'] = $result[0]['lock_endtime']; + return $arr; + + } // if + // no locking configured + return false; + } // eo setLockRecord + + /** + * Returns username for a fe_user_uid + * + * @param int $uid fe_user_uid + * @param $tx_db_pi1 + * @return string username + */ + function getFEUserName($uid, &$tx_db_pi1) { + $query = "SELECT username FROM `fe_users` WHERE `uid`='" . $uid . "'"; + $this->db->doQuery(T3, $query, $result, EXPECT_1); + $username = ($result['username']) ?: "anonymous"; + return $username; + } + + /** + * Create a unique directory in $path + * + * @param string $path path + * @return string path/uniqedir + * @throws codeException + */ + function createUniqueDir($path) { + // Try max. 20 times + for ($i = 0; $i < 20; $i++) { + $dirname = $this->randomAlphaNum(5); + $dirpath = $path . "/" . $dirname; + + if (!file_exists($dirpath)) { + mkdir($dirpath, 0700, true); + return $dirpath; + } + } + // Too many tries without success + throw new CodeReportException ("Could not create unique directory.", __FILE__, __LINE__); + } // eo createUniqueDir + + /** + * Create a ToolTip: $toolTip[0] and $toolTip[1] have to inserted in HTML code accordingly. + * + * @param string $note Text to be shown in the tooltip + * @return array $toolTip $toolTip[0]: JS to show '$toolTip[1]'. + * $toolTip[1]: '<span>...</span>' with the tooltip text. + */ + public function createToolTip($note) { + static $count = 0; + + $toolTipIndex = 'tooltip.' . $GLOBALS["TSFE"]->currentRecord . '.' . ++$count; + $toolTip = array(); + + // Expample: <img src="fileadmin/icons/bullet-gray.gif" onmouseover="document.getElementById('gm167979').style.display='block';" onmouseout="document.getElementById('gm167979').style.display='none';" /> + $toolTip[0] = " onmouseover=\"document.getElementById('" . $toolTipIndex . "').style.display='block';\" onmouseout=\"document.getElementById('" . $toolTipIndex . "').style.display='none';\""; + + // Example: <span id="gm167979" style="display:none; position:absolute; border:solid 1px black; background-color:#F9F3D0; padding:3px;">My pesonal tooltip</span> + $toolTip[1] = '<span id="' . $toolTipIndex . '" style="display:none; position:absolute; border:solid 1px black; background-color:#F9F3D0; padding:3px;">' . $note . '</span>'; + + return ($toolTip); + } // createToolTip() + +} diff --git a/qfq/report/Variables.php b/qfq/report/Variables.php new file mode 100644 index 000000000..ab8f4970d --- /dev/null +++ b/qfq/report/Variables.php @@ -0,0 +1,159 @@ +<?php +/*************************************************************** + * Copyright notice + * + * (c) 2010 Glowbase GmbH <support@glowbase.com> + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + ***************************************************************/ + +namespace qfq; + +//use qfq; + +class Variables { + + public $resultArray = array(); + + // TODO to explain + private $tt_content_uid = 0; + + /** + * @param int $tmp_ttcontent_uid + */ + public function __construct($tmp_ttcontent_uid = 0) { + + // specified once during initialisation. + $this->tt_content_uid = $tmp_ttcontent_uid; + + } + + /** + * Matches on the variables ~1.2name and substitutes them with the values + * + * @param string $text + * @return mixed + */ + public function doVariables($text) { + $str = preg_replace_callback("/(~([a-zA-Z0-9._])*)/", array($this, 'replaceVariables'), $text); + return $str; + } + + /** + * Callbackfunction called by variableSQL() + * Replaces the variablenames whith the value from the resultArray + * + * @param $matches + * @return string The content that is displayed on the website + * @internal param string $content : The PlugIn content + * @internal param array $conf : The PlugIn configuration + */ + public function replaceVariables($matches) { + + // variablename: ~10.20.column + $sqlVariable = $matches[1]; + + // index of last '.' + $pos = strrpos($sqlVariable, "."); + + $replace = $this->resultArray[substr($sqlVariable, 1, $pos)][substr($sqlVariable, $pos + 1, strlen($sqlVariable))]; + + return (isset($this->resultArray[substr($sqlVariable, 1, $pos)][substr($sqlVariable, $pos + 1, strlen($sqlVariable))]) ? $replace : $sqlVariable); + } + + /** + * Collect Global Variables + * + * @param void + * @return array with global variables which might be replaced + */ + public function collectGlobalVariables() { + $arr = array(); + + $arr["REMOTE_ADDR"] = $_SERVER["REMOTE_ADDR"]; + $arr["HTTP_HOST"] = $_SERVER["HTTP_HOST"]; + $arr["REQUEST_URI"] = $_SERVER["REQUEST_URI"]; +// $arr["fe_user_uid"] = $GLOBALS["TSFE"]->fe_user->user["uid"]?:'-'; +// $arr["fe_user"] = $GLOBALS["TSFE"]->fe_user->user["username"]?:'-'; +// $arr["be_user_uid"] = $GLOBALS['BE_USER']->user["uid"]?:'-'; +// $arr["page_id"] = $GLOBALS["TSFE"]->id; +// $arr["page_type"] = $GLOBALS["TSFE"]->type; +// $arr["page_language_uid"] = $GLOBALS["TSFE"]->sys_language_uid; +// $arr["ttcontent_uid"] = $this->tt_content_uid; +// $protocol = (!$_SERVER["HTTPS"] || $_SERVER["HTTPS"]=="off")?"http":"https"; +// $arr["url"] = $protocol . "://" . $arr["HTTP_HOST"]; +// if($_SERVER["SERVER_PORT"] != 80) +// $arr["url"] .= ":" . $_SERVER["SERVER_PORT"]; +// $arr["url"] .= $arr["REQUEST_URI"]; + + // Add all variables from ext_localconf + // database aliases can be used in form sql queries (e.g. select * from "~global.t3_name".fe_users...) + // localconf can be used to configure an application +// $tmp=array(); +// $this->linearizeArray($GLOBALS['TYPO3_CONF_VARS'][FORMREPORT], $tmp); + + // remove anything that contains "_password" "_username" in the key to prevent the webmaster from doing something stupid +// foreach($tmp as $key => $value) { +// if(!strstr($key, "_password") && !strstr($key, "_username")) +// $arr[$key]=$value; +// } + + // Add t3 db name too +// require(PATH_typo3conf.'localconf.php'); + //TODO: $typo_db kommt von T3: PHPSTorm weiss das nicht und meckert hier. Es ist auch nicht gut das die globale Variable genommen wird. Umbauen auf etwas sinnvollerers! + $typo_db = ''; + $arr["t3_name"] = $typo_db; + + return ($arr); + } // eo collectGlobalVariables + + public function linearizeArray($arr, &$return, $keypath = "") { + if (is_array($arr)) { + foreach ($arr as $key => $value) { + $this->linearizeArray($value, $return, $keypath . "_" . $key); + } + } else { + $return[ltrim($keypath, "_")] = $arr; + } + } // linearizeArray() + + /** + * Method to circumvate 'Undefined index' + * + * @param $varName + * @param $firstLevel + * @return string + */ + public function get($varName, $firstLevel, $secondLevel = false) { + if (!isset($this->$varName)) + $this->$varName = array(); + + if (!isset($this->$varName[$firstLevel])) + $this->$varName[$firstLevel] = array(); + + if ($secondLevel !== false && !isset($this->$varName[$firstLevel][$secondLevel])) + $this->$varName[$firstLevel][$secondLevel] = array(); + + if ($secondLevel === false) { + return $this->$varName[$firstLevel]; + } else { + return $this->$varName[$firstLevel][$secondLevel]; + } + return ''; + } +} -- GitLab