'', 'pid' => '', 'row' => '', 'debug_level' => '0', 'full_level' => ''); private $phpUnit = false; private $showDebugInfoFlag = false; private $flagFillStoreRecord = true; /** * Report constructor. * * @param array $t3data * @param Evaluate $eval * @param bool $phpUnit * @throws CodeException * @throws DbException * @throws UserFormException */ public function __construct(array $t3data, Evaluate $eval, $phpUnit = false) { $this->phpUnit = $phpUnit; Support::setIfNotSet($t3data, "uid", 0); $this->sip = new Sip($phpUnit); if ($phpUnit) { $this->sip->sipUniqId('badcaffee1234'); //TODO Webserver Umgebung besser faken $_SERVER['REQUEST_URI'] = 'localhost'; } $this->store = Store::getInstance(); $this->showDebugInfoFlag = (Support::findInSet(SYSTEM_SHOW_DEBUG_INFO_YES, $this->store->getVar(SYSTEM_SHOW_DEBUG_INFO, STORE_SYSTEM))); $this->checkUpdateSqlLog(); $this->pageDefaults[DEFAULT_QUESTION]["pagec"] = "Please confirm!:info"; $this->pageDefaults[DEFAULT_QUESTION]["paged"] = "Do you really want to delete the record?:warning"; $this->pageDefaults[DEFAULT_ICON]["paged"] = TOKEN_DELETE; $this->pageDefaults[DEFAULT_ICON]["pagee"] = TOKEN_EDIT; $this->pageDefaults[DEFAULT_ICON]["pageh"] = TOKEN_HELP; $this->pageDefaults[DEFAULT_ICON]["pagei"] = TOKEN_INFO; $this->pageDefaults[DEFAULT_ICON]["pagen"] = TOKEN_NEW; $this->pageDefaults[DEFAULT_ICON]["pages"] = TOKEN_SHOW; $this->pageDefaults[DEFAULT_BOOTSTRAP_BUTTON]["pagec"] = TOKEN_BOOTSTRAP_BUTTON; $this->pageDefaults[DEFAULT_BOOTSTRAP_BUTTON]["paged"] = TOKEN_BOOTSTRAP_BUTTON; $this->pageDefaults[DEFAULT_BOOTSTRAP_BUTTON]["pagee"] = TOKEN_BOOTSTRAP_BUTTON; $this->pageDefaults[DEFAULT_BOOTSTRAP_BUTTON]["pagen"] = TOKEN_BOOTSTRAP_BUTTON; $this->pageDefaults[DEFAULT_BOOTSTRAP_BUTTON]["pages"] = TOKEN_BOOTSTRAP_BUTTON; // Default should already set in QuickFormQuery() Constructor $this->dbIndexData = $this->store->getVar(TOKEN_DB_INDEX, STORE_TYPO3); if ($this->dbIndexData === false) { $this->dbIndexData = DB_INDEX_DEFAULT; } $this->db = new Database($this->dbIndexData); $this->variables = new Variables($eval, $t3data["uid"]); $this->link = new Link($this->sip, $this->dbIndexData, $phpUnit); // Set static values, which won't change during this run. $this->fr_error["pid"] = isset($this->variables->resultArray['global.']['page_id']) ? $this->variables->resultArray['global.']['page_id'] : 0; $this->fr_error["uid"] = $t3data['uid']; $this->fr_error["debug_level"] = 0; // Sanitize function for POST and GET Parameters. // Merged URL-Parameter (key1, id etc...) in resultArray. $this->variables->resultArray = array_merge($this->variables->resultArray, array("global." => $this->variables->collectGlobalVariables())); } /** * If a variable 'sqlLog' is given in STORE_TYPO3 (=Bodytext) make them relative to SYSTEM_PATH_EXT and copy it to * STORE_SYSTEM */ private function checkUpdateSqlLog() { $sqlLog = $this->store->getVar(TYPO3_SQL_LOG, STORE_TYPO3); if (false !== $sqlLog) { if ($sqlLog != '' && $sqlLog[0] !== '/') { $sqlLog = $this->store->getVar(SYSTEM_PATH_EXT, STORE_SYSTEM) . '/' . $sqlLog; } $this->store->setVar(SYSTEM_SQL_LOG, $sqlLog, STORE_SYSTEM); } $sqlLogMode = $this->store->getVar(TYPO3_SQL_LOG_MODE, STORE_TYPO3); if (false !== $sqlLogMode) { $this->store->setVar(SYSTEM_SQL_LOG_MODE, $sqlLogMode, STORE_SYSTEM); } } /** * Main function. Parses bodytext and iterates over all queries. * * @param $bodyText * @param bool $flagFillStoreRecord * @return string * @throws CodeException * @throws DbException * @throws UserFormException * @throws UserReportException */ public function process($bodyText, $flagFillStoreRecord = true) { //phpUnit Test: clean environment $this->frArray = array(); $this->indexArray = array(); $this->levelCount = 0; $this->flagFillStoreRecord = $flagFillStoreRecord; // Iteration over Bodytext $ttLineArray = explode("\n", $bodyText); foreach ($ttLineArray as $index => $line) { // Fill $frArray, $indexArray, $resultArray $this->parseLine($line); } // Sort array $this->sortIndexArray($this->indexArray, $this->generateSortArg()); // Report $content = $this->triggerReport(); return $content; } /** * 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 * * @throws UserReportException */ private function parseLine($ttLine) { // 10.50.5.sql = select ... $arr = explode("=", trim($ttLine), 2); // no elements or only one: do nothing if (count($arr) < 2) { return; } // 10.50.5.sql $key = strtolower(trim($arr[0])); // comment ? if (empty($key) || $key[0] === "#") { return; } // select ... - if needed, trim surrounding single ticks $value = trim($arr[1]); $value = OnString::trimQuote($value); // 10.50.5.sql $arrKey = explode('.', $key); // frCmd = "sql" $frCmd = $arrKey[count($arrKey) - 1]; if (strpos('|' . strtolower(TOKEN_VALID_LIST) . '|', '|' . $frCmd . '|') === false) { throw new UserReportException ("Unknown token: $frCmd in Line '$ttLine''", ERROR_UNKNOWN_TOKEN); } // 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); } } /** * @param $level * @param $frCmd * @param $value */ private function setLine($level, $frCmd, $value) { // 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 === TOKEN_FORM || $frCmd === TOKEN_SQL) { if ($frCmd === TOKEN_SQL) { // Remember max level $this->levelCount = max(substr_count($level, '.') + 1, $this->levelCount); // $indexArray[10][50][5] $this->indexArray[] = explode(".", $level); } // set defaults if ($frCmd === TOKEN_SQL) { $arr = explode('|', TOKEN_VALID_LIST); foreach ($arr as $key) { if (!isset($this->frArray[$level . "." . $key])) { $this->frArray[$level . "." . $key] = ''; } } } } /** * 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 * @param bool|true $ascending */ private function sortIndexArray(array &$ary, $clause, $ascending = true) { $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); // TODO: at the moment, $sortFn() triggers some E_NOTICE warnings. We stop these here for a short time. $errorSet = error_reporting(); error_reporting($errorSet & ~E_NOTICE); usort($ary, $sortFn); error_reporting($errorSet); } } /** * generateSortArg * * @return string */ private function generateSortArg() { $sortArg = ""; for ($i = 0; $i < $this->levelCount; $i++) { $sortArg = $sortArg . $i . " ASC, "; } $sortArg = substr($sortArg, 0, strlen($sortArg) - 2); return $sortArg; } /** * 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 with the level mode 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 array $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 DbException * @throws UserFormException * @throws UserReportException */ private function triggerReport($cur_level = 1, array $super_level_array = array(), $counter = 0) { $keys = array(); $stat = array(); $lineDebug = 0; $content = ""; $rowTotal = 0; // CurrentLevel "10.10.50" if (isset($this->indexArray[$counter]) && is_array($this->indexArray[$counter])) { $full_level = implode(".", $this->indexArray[$counter]); } else { $full_level = ''; } // Superlevel "10.10" if (isset($super_level_array) && is_array($super_level_array)) { $full_super_level = implode(".", $super_level_array); } else { $full_super_level = ''; } //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])) { ++$counter; if (isset($this->indexArray[$counter]) && is_array($this->indexArray[$counter])) { $full_level = implode(".", $this->indexArray[$counter]); } else { $full_level = ''; } continue; } // Set debug, if one is specified else keep the parent one. $lineDebug = $this->getValueParentDefault(TOKEN_DEBUG, $full_super_level, $full_level, $cur_level, 0); // Prepare Error reporting $this->store->setVar(SYSTEM_SQL_RAW, $this->frArray[$full_level . "." . TOKEN_SQL], STORE_SYSTEM); $this->store->setVar(SYSTEM_REPORT_FULL_LEVEL, $full_level, STORE_SYSTEM); // Prepare SQL: replace variables. Actual 'line.total' or 'line.count' will recalculated: don't replace them now! unset($this->variables->resultArray[$full_level . ".line."]["total"]); unset($this->variables->resultArray[$full_level . ".line."]["count"]); $sql = $this->variables->doVariables($this->frArray[$full_level . "." . TOKEN_SQL]); $this->store->setVar(SYSTEM_SQL_FINAL, $sql, STORE_SYSTEM); //Execute SQL. All errors have been already catched. unset($result); $result = $this->db->sql($sql, ROW_KEYS, array(), '', $keys, $stat); // If an array is returned, $sql was a query, otherwise an 'insert', 'update', 'delete', ... // Query: total nummber of rows // insert, delete, update: number of affected rows $rowTotal = isset($stat[DB_NUM_ROWS]) ? $stat[DB_NUM_ROWS] : $stat[DB_AFFECTED_ROWS]; $this->variables->resultArray[$full_level . ".line."]["total"] = $rowTotal; $this->variables->resultArray[$full_level . ".line."]["count"] = is_array($result) ? 1 : 0; $this->variables->resultArray[$full_level . ".line."]["insertId"] = isset($stat[DB_INSERT_ID]) ? $stat[DB_INSERT_ID] : 0; $content .= $this->variables->doVariables($this->frArray[$full_level . "." . TOKEN_SHEAD]); // HEAD: If there is at least one record, do 'head'. if ($rowTotal > 0) { $content .= $this->variables->doVariables($this->frArray[$full_level . "." . TOKEN_HEAD]); } if (is_array($result)) { // Prepare row alteration $arrRbgd = explode("|", $this->frArray[$full_level . "." . TOKEN_RBGD], 2); if (count($arrRbgd) < 2) { $arrRbgd[] = ''; $arrRbgd[] = ''; } //--------------------------------- // Process each row of resultset $columnValueSeparator = ""; $rowIndex = 0; foreach ($result as $row) { // record number counter $this->variables->resultArray[$full_level . ".line."]["count"] = ++$rowIndex; // replace {{.line.count}} and {{.line.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]); } // SEP set separator (empty on first run) $content .= $columnValueSeparator; $columnValueSeparator = $this->variables->doVariables($this->frArray[$full_level . "." . TOKEN_RSEP]); // RBEG $rbeg = $this->variables->doVariables($this->frArray[$full_level . "." . TOKEN_RBEG]); // RBGD: even/odd rows $content .= str_replace(TOKEN_RBGD, $arrRbgd[$rowIndex % 2], $rbeg); //----------------------------- // COLUMNS: Collect all columns $content .= $this->collectRow($row, $keys, $full_level, $rowIndex); // REND $content .= $this->variables->doVariables($this->frArray[$full_level . "." . TOKEN_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 . "." . TOKEN_RENR]); } } if ($rowTotal > 0) { // tail $content .= $this->variables->doVariables($this->frArray[$full_level . "." . TOKEN_TAIL]); } else { // althead $content .= $this->variables->doVariables($this->frArray[$full_level . "." . TOKEN_ALT_HEAD]); // altsql $sql = $this->variables->doVariables($this->frArray[$full_level . "." . TOKEN_ALT_SQL]); if (!empty($sql)) { $result = $this->db->sql($sql, ROW_KEYS, array(), '', $keys, $stat); foreach ($result as $row) { $rowIndex = 0; $content .= $this->collectRow($row, $keys, $full_level, $rowIndex); } } } $content .= $this->variables->doVariables($this->frArray[$full_level . "." . TOKEN_STAIL]); ++$counter; if (isset($this->indexArray[$counter]) && is_array($this->indexArray[$counter])) { $full_level = implode(".", $this->indexArray[$counter]); } else { $full_level = ''; } } return $content; } /** * 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 (!empty($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); } /** * 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 CodeException * @throws DbException * @throws DownloadException * @throws UserFormException * @throws UserReportException */ private function collectRow(array $row, array $keys, $full_level, $rowIndex) { $content = ""; $assoc = array(); $fsep = ''; for ($ii = 0; $ii < count($keys); $ii++) { // Debugging $this->store->setVar(SYSTEM_REPORT_COLUMN_INDEX, $ii + 1, STORE_SYSTEM); $this->store->setVar(SYSTEM_REPORT_COLUMN_NAME, $keys[$ii], STORE_SYSTEM); $this->store->setVar(SYSTEM_REPORT_COLUMN_VALUE, $row[$ii], STORE_SYSTEM); $flagOutput = false; $renderedColumn = $this->renderColumn($ii, $keys[$ii], $row[$ii], $full_level, $rowIndex, $flagOutput); $keyAssoc = OnString::stripFirstCharIf(TOKEN_COLUMN_CTRL, $keys[$ii]); if ($keyAssoc != '') { $assoc[$keyAssoc] = $row[$ii]; $assoc[REPORT_TOKEN_FINAL_VALUE . $keyAssoc] = $renderedColumn; } if ($flagOutput) { //prints $content .= $this->variables->doVariables($fsep); $content .= $this->variables->doVariables($this->frArray[$full_level . "." . TOKEN_FBEG]); $content .= $renderedColumn; $content .= $this->variables->doVariables($this->frArray[$full_level . "." . TOKEN_FEND]); $fsep = $this->frArray[$full_level . "." . TOKEN_FSEP]; } } if ($this->flagFillStoreRecord) { $this->store->appendToStore($assoc, STORE_RECORD); } return ($content); } /** * Renders column depending of column name (if name is a reserved column name) * * @param string $columnIndex * @param string $columnName * @param string $columnValue * @param string $full_level * @param string $rowIndex * @param $flagOutput * * @return string rendered column * @throws CodeException * @throws DbException * @throws DownloadException * @throws UserFormException * @throws UserReportException */ private function renderColumn($columnIndex, $columnName, $columnValue, $full_level, $rowIndex, &$flagOutput) { $content = ""; $flagControl = false; $flagOutput = true; $dummy = false; // Special column name: '_...'? Empty column names are allowed: check with isset if (isset($columnName[0]) && $columnName[0] === TOKEN_COLUMN_CTRL) { $flagControl = true; $columnName = substr($columnName, 1); // Special column name and hide output: '__...'? (double '_' at the beginning) if (isset($columnName[0]) && $columnName[0] === TOKEN_COLUMN_CTRL) { $flagOutput = false; $columnName = substr($columnName, 1); } } //TODO: reserved names,not starting with '_' will be still accepted - stop this! switch ($columnName) { case COLUMN_LINK: $content .= $this->link->renderLink($columnValue); break; case COLUMN_EXEC: $rc = ''; $content .= Support::qfqExec($columnValue, $rc); break; // Uppercase 'P' case COLUMN_PPAGE: case COLUMN_PPAGEC: case COLUMN_PPAGED: case COLUMN_PPAGEE: case COLUMN_PPAGEH: case COLUMN_PPAGEI: case COLUMN_PPAGEN: case COLUMN_PPAGES: $lowerColumnName = strtolower($columnName); $tokenizedValue = $this->doFixColPosPage($columnName, $columnValue); $linkValue = $this->doPage($lowerColumnName, $tokenizedValue); $content .= $this->link->renderLink($linkValue); break; // Lowercase 'P' case COLUMN_PAGE: case COLUMN_PAGEC: case COLUMN_PAGED: case COLUMN_PAGEE: case COLUMN_PAGEH: case COLUMN_PAGEI: case COLUMN_PAGEN: case COLUMN_PAGES: $linkValue = $this->doPage($columnName, $columnValue); $content .= $this->link->renderLink($linkValue); break; case COLUMN_PPDF: case COLUMN_FFILE: case COLUMN_ZZIP: $lowerColumnName = strtolower($columnName); $tokenizedValue = $this->doFixColPosDownload($columnValue); $linkValue = $this->doDownload($lowerColumnName, $tokenizedValue); $content .= $this->link->renderLink($linkValue); break; case COLUMN_PDF: case COLUMN_FILE: case COLUMN_ZIP: $linkValue = $this->doDownload($columnName, $columnValue); $content .= $this->link->renderLink($linkValue); break; case COLUMN_THUMBNAIL: if ($this->thumbnail == null) { $this->thumbnail = new Thumbnail(); } $content .= $this->thumbnail->process($columnValue); break; case COLUMN_MONITOR: if ($this->monitor == null) { $this->monitor = new Monitor(); } $content .= $this->monitor->process($columnValue); break; case COLUMN_MIME_TYPE: $content .= HelperFile::getMimeType($columnValue, true); break; case COLUMN_FILE_SIZE: $content .= filesize($columnValue); break; case COLUMN_NL2BR: $content .= nl2br($columnValue); break; case COLUMN_HTMLENTITIES: $content .= htmlentities($columnValue); break; case COLUMN_STRIPTAGS: $content .= strip_tags($columnValue); break; case "bullet": if ($columnValue === '') { break; } // r:3|B: $linkValue = TOKEN_RENDER . ":3|" . TOKEN_BULLET . ":" . $columnValue; $content .= $this->link->renderLink($linkValue); break; case "check": if ($columnValue === '') { break; } // "r:3|C: $linkValue = TOKEN_RENDER . ":3|" . TOKEN_CHECK . ":" . $columnValue; $content .= $this->link->renderLink($linkValue); break; case "img": // "|[alttext]|[text behind]" renders to: [alttext][text behind] if (empty($columnValue)) { break; } $mailConfig = explode("|", $columnValue, 3); // Fake values for tmp[1], tmp[2] to suppress access errors. $mailConfig[] = ''; $mailConfig[] = ''; if (empty($mailConfig[0])) { break; } $attribute = Support::doAttribute('src', $mailConfig[0]); $attribute .= Support::doAttribute('alt', $mailConfig[1]); $content .= '' . $mailConfig[2]; break; case "mailto": // "|[Real Name]" renders to (encrypted via JS): OR [Real Name] $mailConfig = explode("|", $columnValue, 2); if (empty($mailConfig[0])) { break; } $t1 = explode("@", $mailConfig[0], 2); $content .= "'; break; case "sendmail": $sendMail = new SendMail(); $mailConfig = $sendMail->parseStringToArray($columnValue); if (count($mailConfig) < 4) { throw new UserReportException ("Too few parameter for sendmail: $columnValue", ERROR_TOO_FEW_PARAMETER_FOR_SENDMAIL); } $mailConfig[SENDMAIL_TOKEN_SRC] = "Report: T3 pageId=" . $this->store->getVar('pageId', STORE_TYPO3) . ", T3 ttcontentId=" . $this->store->getVar('ttcontentUid', STORE_TYPO3) . ", Level=" . $full_level; $sendMail->process($mailConfig); break; case "vertical": // '|[angle]|[width]|[height]|[tag]' , width and height 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"; $extra = "width:$width; "; # height if ($arr[3]) { $extra .= "height:" . $arr[3] . "; "; } # tag if ($arr[4]) { $tag = explode(" ", trim($arr[4]), 2); $tag_open = "<" . $arr[4] . " "; $tag_close = ""; } else { $tag_open = "
' . $arr[0] . $tag_close; break; default : if ($flagControl) { // Columnnames starting with '+' will wrap the content. EG "SELECT 'apple' AS '+h1 class=best'" >>

apple

if (isset($columnName[0]) && $columnName[0] == COLUMN_WRAP_TOKEN && isset($columnName[1])) { $content = Support::wrapTag('<' . substr($columnName, 1) . '>', $columnValue); break; } $flagOutput = false; } else { // No special Columnname: just add the column value. $content .= $columnValue; } break; } // Always save column values, even if they are hidden. $this->variables->resultArray[$full_level . "."][$columnName] = ($content == '' && $flagControl) ? $columnValue : $content; return $content; } /** * 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: * ------------- * [[¶m=value&...]] | [text] | [tooltip] | [msgbox] | [class] | [target] | [render mode] * * param[0]: [¶m=value&...] * param[2]: text * param[3]: tooltip * param[4]: msgbox * param[5]: class * param[6]: target * param[7]: render mode * @throws UserReportException */ private function doFixColPosPage($columnName, $columnValue) { $tokenList = ""; if (empty($columnName)) { return ''; } // Split definition $allParam = explode('|', $columnValue); if (count($allParam) > 8) { throw new UserReportException ("Too many parameter (max=8): $columnValue", ERROR_TOO_MANY_PARAMETER); } // First Parameter: Split PageId|PageAlias and URL Params $firstParam = explode('&', $allParam[0], 2); if (empty($firstParam[1])) { $firstParam[] = ''; } switch ($columnName) { case COLUMN_PPAGED: // no pageid /pagealias given. $tokenList .= $this->composeLinkPart(TOKEN_URL_PARAM, $allParam[0]); break; default: $tokenList .= $this->composeLinkPart(TOKEN_PAGE, $firstParam[0]); // -- PageID -- $tokenList .= $this->composeLinkPart(TOKEN_URL_PARAM, $firstParam[1]); } if (isset($allParam[1]) && $allParam[1] !== '') { $tokenList .= $this->composeLinkPart(TOKEN_TEXT, $allParam[1]); // -- Text -- } if (isset($allParam[2]) && $allParam[2] !== '') { $tokenList .= $this->composeLinkPart(TOKEN_TOOL_TIP, $allParam[2]); // -- tooltip -- } if (isset($allParam[3]) && $allParam[3] !== '') { $text = isset($this->pageDefaults[DEFAULT_QUESTION][$columnName]) ? $this->pageDefaults[DEFAULT_QUESTION][$columnName] : ''; $tokenList .= $this->composeLinkPart(TOKEN_QUESTION, $allParam[3], $text); // -- msgbox } if (isset($allParam[4]) && $allParam[4] !== '') { $tokenList .= $this->composeLinkPart(TOKEN_CLASS, $allParam[4]); // -- class -- } if (isset($allParam[5]) && $allParam[5] !== '') { $tokenList .= $this->composeLinkPart(TOKEN_TARGET, $allParam[5]); // -- target -- } if (isset($allParam[6]) && $allParam[6] !== '') { $tokenList .= $this->composeLinkPart(TOKEN_RENDER, $allParam[6]); // -- render mode -- } if (!isset($allParam[7])) { $allParam[7] = '1'; // if no SIP behaviour defined: sip is set } $tokenList .= $this->composeLinkPart(TOKEN_SIP, $allParam[7]); // -- SIP -- if (isset($this->pageDefaults[DEFAULT_ICON][$columnName])) { $tokenList .= $this->pageDefaults[DEFAULT_ICON][$columnName] . "|"; } return ($tokenList); } /** * Renders Download: convert position content to token content. Respect default values. * | | <1: urlparam|file> | <2: urlparam|file> | ... | * * @param string $columnValue * * @return string rendered link * @throws UserReportException */ private function doFixColPosDownload($columnValue) { $tokenList = ''; if ($columnValue == '') { throw new UserReportException ("Missing parameter for " . DOWNLOAD_MODE_PDF . '/' . DOWNLOAD_MODE_FILE . '/' . DOWNLOAD_MODE_ZIP, ERROR_MISSING_REQUIRED_PARAMETER); } // Split definition $allParam = explode('|', $columnValue); $value = array_shift($allParam); if ($value !== null) { $tokenList .= $this->composeLinkPart(TOKEN_DOWNLOAD, $value); // -- d: -- } $value = array_shift($allParam); if ($value !== null) { $tokenList .= $this->composeLinkPart(TOKEN_TEXT, $value); // -- t: -- } // Take all remaining parameter as TOKEN_URL_PARAM or TOKEN_FILE while (null !== ($value = array_shift($allParam))) { $token = (strpos($value, '=')) ? TOKEN_URL_PARAM : TOKEN_FILE; $tokenList .= $this->composeLinkPart($token, $value); // -- U: | f: -- } return ($tokenList); } /** * 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 ($value === '') { $value = $defaultValue; } if ($value !== '') { return ($qualifier . ":" . $value . "|"); } return ''; } /** * Renders _pageX: extract token and determine if any default value has to be applied * * @param string $columnName * @param string $columnValue * * @return string rendered link */ private function doPage($columnName, $columnValue) { $defaultQuestion = ''; $defaultActionDelete = ''; $param = explode('|', $columnValue); # get all default values, depending on the columnname $defaultImage = isset($this->pageDefaults[DEFAULT_ICON][$columnName]) ? $this->pageDefaults[DEFAULT_ICON][$columnName] : ''; $defaultSip = TOKEN_SIP; if ($columnName === COLUMN_PAGED) { $defaultActionDelete = TOKEN_ACTION_DELETE . ':' . TOKEN_ACTION_DELETE_REPORT; } $defaultBootstrapButton = isset($this->pageDefaults[DEFAULT_BOOTSTRAP_BUTTON][$columnName]) ? $this->pageDefaults[DEFAULT_BOOTSTRAP_BUTTON][$columnName] : ''; # define default question only, if pagetype needs a question if (!empty($this->pageDefaults[DEFAULT_QUESTION][$columnName])) { $defaultQuestion = 'q:' . $this->pageDefaults[DEFAULT_QUESTION][$columnName]; } foreach ($param as $key) { switch (substr($key, 0, 1)) { case TOKEN_PICTURE: case TOKEN_EDIT: case TOKEN_NEW: case TOKEN_DELETE: case TOKEN_HELP: case TOKEN_INFO: case TOKEN_SHOW: case TOKEN_BULLET: case TOKEN_CHECK: $defaultImage = ''; // if any of the img token is given: no default break; case TOKEN_SIP: $defaultSip = ''; // if a hash definition is given: no default break; case TOKEN_QUESTION: $defaultQuestion = ''; // if a question is given: no default break; case TOKEN_ACTION_DELETE: $defaultActionDelete = ''; break; case TOKEN_BOOTSTRAP_BUTTON: // if a bootstrapButton setting is given: no default $defaultBootstrapButton = ''; break; default: break; } } $columnValue .= "|"; // append defaults if ($defaultActionDelete !== '') { $columnValue .= $defaultActionDelete . "|"; } if ($defaultImage !== '') { $columnValue .= $defaultImage . "|"; } if ($defaultSip !== '') { $columnValue .= $defaultSip . "|"; } if ($defaultQuestion !== '') { $columnValue .= $defaultQuestion . "|"; } if ($defaultBootstrapButton !== '') { $columnValue .= $defaultBootstrapButton . "|"; } return ($columnValue); } /** * Renders _download: extract token and determine if any default value has to be applied * [d:][u:][f:file][t:][a:]|[o:]|[c:]|[r:] * * @param string $columnName * @param string $columnValue * * @return string rendered link * @throws CodeException */ private function doDownload($columnName, $columnValue) { if ($columnValue == '') { return ''; } $columNameToMode = [COLUMN_PDF => DOWNLOAD_MODE_PDF, COLUMN_FILE => DOWNLOAD_MODE_FILE, COLUMN_ZIP => DOWNLOAD_MODE_ZIP]; $param = explode('|', $columnValue); // Depending on the $columnName, get mode. if (!isset($columNameToMode[$columnName])) { throw new CodeException("Unexpected columnname: $columnName", ERROR_UNEXPECTED_TYPE); } $defaultMode = TOKEN_DOWNLOAD_MODE . ':' . $columNameToMode[$columnName]; # get all default values, depending on the columnname $defaultSip = TOKEN_SIP; $defaultDownload = TOKEN_DOWNLOAD; foreach ($param as $key) { switch (substr($key, 0, 1)) { case TOKEN_SIP: $defaultSip = ''; break; case TOKEN_DOWNLOAD: $defaultDownload = ''; break; case TOKEN_DOWNLOAD_MODE: $defaultMode = ''; break; case TOKEN_RENDER: if (isset($key[2]) && $key[2] == '5') { return ''; } break; default: break; } } $columnValue .= "|"; if ($defaultSip !== '') { $columnValue .= $defaultSip . "|"; } if ($defaultDownload !== '') { $columnValue .= $defaultDownload . "|"; } if ($defaultMode !== '') { $columnValue .= $defaultMode . "|"; } return ($columnValue); } /** * Generate SortArgument * * @param $variable * * @return string */ private function getResultArrayIndex($variable) { $variable = substr($variable, 1, strlen($variable)); return "[" . preg_replace_callback("/[a-z]/", "replaceToIndex", $variable) . "][" . preg_replace_callback("/[^a-z]/", "replaceToIndex", $variable) . "]"; } /** * @param $arr1 * @param $arr2 * * @return bool */ private function compareArraystart($arr1, $arr2) { for ($i = 0; $i < count($arr1); $i++) { if ($arr1[$i] != $arr2[$i]) { return false; } } return true; } /** * @param $arr1 * @param $arr2 * * @return bool */ private function compareArraylength($arr1, $arr2) { if (count($arr1) + 1 == count($arr2)) { return true; } return false; } }