From 1d6095baabfcaf9ce0ef415868250d9363fb7ab3 Mon Sep 17 00:00:00 2001
From: Carsten  Rose <carsten.rose@math.uzh.ch>
Date: Sat, 16 Jun 2018 00:29:08 +0200
Subject: [PATCH] F5885 show 'sql.log' in FE - first server side
 implementation.

---
 extension/qfq/qfq/AbstractBuildForm.php | 112 +++++++++++++++++-
 extension/qfq/qfq/Constants.php         |  11 +-
 extension/qfq/qfq/QuickFormQuery.php    |   2 -
 extension/qfq/qfq/helper/Support.php    |   2 +-
 extension/qfq/qfq/report/Download.php   |   8 +-
 extension/qfq/qfq/report/Link.php       |   2 +
 extension/qfq/qfq/report/Monitor.php    | 149 ++++++++++++++++++++++++
 extension/qfq/qfq/report/Report.php     |  40 +++----
 extension/qfq/qfq/report/Thumbnail.php  |   1 +
 extension/qfq/qfq/store/Sip.php         |   1 -
 10 files changed, 301 insertions(+), 27 deletions(-)
 create mode 100644 extension/qfq/qfq/report/Monitor.php

diff --git a/extension/qfq/qfq/AbstractBuildForm.php b/extension/qfq/qfq/AbstractBuildForm.php
index 6dc85c838..4be683fbc 100644
--- a/extension/qfq/qfq/AbstractBuildForm.php
+++ b/extension/qfq/qfq/AbstractBuildForm.php
@@ -86,6 +86,8 @@ abstract class AbstractBuildForm {
      * @param array $feSpecAction
      * @param array $feSpecNative
      * @param array $db
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function __construct(array $formSpec, array $feSpecAction, array $feSpecNative, array $db = null) {
         $this->formSpec = $formSpec;
@@ -172,6 +174,8 @@ abstract class AbstractBuildForm {
      * @param array $latestFeSpecNative
      * @return array|string $mode=LOAD_FORM: The whole form as HTML, $mode=FORM_UPDATE: array of all
      *                        formElement.dynamicUpdate-yes  values/states
+     * @throws CodeException
+     * @throws DbException
      * @throws UserFormException
      */
     public function process($mode, $htmlElementNameIdZero = false, $latestFeSpecNative = array()) {
@@ -247,6 +251,8 @@ abstract class AbstractBuildForm {
      *
      * @param string $mode
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function head($mode = FORM_LOAD) {
         $html = '';
@@ -276,6 +282,8 @@ abstract class AbstractBuildForm {
      *
      * @return string String: <a href="?pageId&sip=....">Edit</a> <small>[sip:..., r:..., urlparam:...,
      *                ...]</small>
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function createFormEditorUrl($form, $recordId, array $param = array()) {
 
@@ -338,6 +346,8 @@ abstract class AbstractBuildForm {
      * Build MD5 from the current record. Return HTML Input element.
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function buildInputRecordHashMd5() {
 
@@ -357,6 +367,9 @@ abstract class AbstractBuildForm {
      * @param $recordId
      *
      * @return string
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
      */
     public function buildRecordHashMd5($tableName, $recordId) {
         $record = array();
@@ -372,6 +385,8 @@ abstract class AbstractBuildForm {
      * Create HTML Input vars to detect bot automatic filling of forms.
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function getHoneypotVars() {
         $html = '';
@@ -442,6 +457,9 @@ abstract class AbstractBuildForm {
      * See: https://www.w3.org/wiki/HTML/Elements/form#HTML_Attributes
      *
      * @return string
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
      */
     public function getEncType() {
 
@@ -457,6 +475,10 @@ abstract class AbstractBuildForm {
      * @param array|string $value
      *
      * @return array|string
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
+     * @throws UserReportException
      */
     private function processReportSyntax($value) {
 
@@ -502,6 +524,10 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return string
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
+     * @throws UserReportException
      */
     public function elements($recordId, $filter = FORM_ELEMENTS_NATIVE, $feIdContainer = 0, array &$json,
                              $modeCollectFe = FLAG_DYNAMIC_UPDATE, $htmlElementNameIdZero = false,
@@ -672,6 +698,10 @@ abstract class AbstractBuildForm {
      * @param array $formElement
      *
      * @return array
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
+     * @throws UserReportException
      */
     private function prepareFillStoreFireLdap(array $formElement) {
 
@@ -767,6 +797,8 @@ abstract class AbstractBuildForm {
      * save/update.
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     private function prepareT3VarsForSave() {
 
@@ -802,6 +834,8 @@ abstract class AbstractBuildForm {
      * Get all elements from STORE_ADDITIONAL_FORM_ELEMENTS and return them as a string.
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     private function buildAdditionalFormElements() {
 
@@ -816,6 +850,8 @@ abstract class AbstractBuildForm {
      * @param array $json
      *
      * @return string  <input type='hidden' name='s' value='<sip>'>
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function buildHiddenSip(array &$json) {
 
@@ -921,6 +957,7 @@ abstract class AbstractBuildForm {
      * @param array $feMode
      *
      * @return array
+     * @throws UserFormException
      */
     private function getJsonFeMode($feMode) {
 
@@ -970,6 +1007,7 @@ abstract class AbstractBuildForm {
      * @param string $addClass
      *
      * @return string
+     * @throws CodeException
      */
     public function buildLabel($htmlFormElementName, $label, $addClass = '') {
         $attributes = Support::doAttribute('for', $htmlFormElementName);
@@ -985,6 +1023,8 @@ abstract class AbstractBuildForm {
      *
      * @param $toolTipNew
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function deriveNewRecordUrlFromExistingSip(&$toolTipNew) {
 
@@ -1048,6 +1088,8 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return string complete rendered HTML input element.
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function buildInput(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
         $textarea = '';
@@ -1192,6 +1234,7 @@ abstract class AbstractBuildForm {
      * @param array $formElement
      *
      * @return string
+     * @throws CodeException
      * @throws UserFormException
      */
     private function typeAheadBuildParam(array &$formElement) {
@@ -1297,6 +1340,7 @@ abstract class AbstractBuildForm {
      * @param bool $flagOmitEmpty
      *
      * @return string
+     * @throws CodeException
      */
     private function getAttributeList(array $formElement, array $attributeList, $flagOmitEmpty = true) {
         $attribute = '';
@@ -1315,6 +1359,7 @@ abstract class AbstractBuildForm {
      *
      * @param bool $cssDisable
      * @return string
+     * @throws CodeException
      * @throws UserFormException
      */
     private function getAttributeFeMode($feMode, $cssDisable = true) {
@@ -1371,6 +1416,7 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE*
      *
      * @return string
+     * @throws CodeException
      * @throws UserFormException
      */
     public function buildCheckbox(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
@@ -1426,6 +1472,7 @@ abstract class AbstractBuildForm {
      * @param array $itemKey
      * @param array $itemValue
      *
+     * @throws CodeException
      * @throws UserFormException
      */
     public function getKeyValueListFromSqlEnumSpec(array $formElement, array &$itemKey, array &$itemValue) {
@@ -1498,6 +1545,7 @@ abstract class AbstractBuildForm {
      * @param string $fieldType
      *
      * @return array
+     * @throws CodeException
      * @throws UserFormException
      */
     private function getItemsForEnumOrSet($column, &$fieldType) {
@@ -1543,6 +1591,7 @@ abstract class AbstractBuildForm {
      * @param array $itemKey
      * @param array $formElement
      *
+     * @throws CodeException
      * @throws UserFormException
      */
     private function prepareCheckboxCheckedUncheckedValue(array $itemKey, array &$formElement) {
@@ -1616,6 +1665,8 @@ abstract class AbstractBuildForm {
      * @param array $json
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function constructCheckboxSingleButton(array $formElement, $htmlFormElementName, $attribute, $value, array &$json) {
         $html = '';
@@ -1674,6 +1725,8 @@ abstract class AbstractBuildForm {
      * @param array $json
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function constructCheckboxSinglePlain(array $formElement, $htmlFormElementName, $attribute, $value, array &$json) {
         $html = '';
@@ -1741,7 +1794,8 @@ abstract class AbstractBuildForm {
      * @param array $formElement
      * @param string $htmlFormElementName
      * @param string $htmlHidden
-     *
+     * @throws CodeException
+     * @throws UserFormException
      */
     private function fillStoreAdditionalFormElementsCheckboxHidden(array $formElement, $htmlFormElementName, $htmlHidden) {
 
@@ -1771,6 +1825,8 @@ abstract class AbstractBuildForm {
      * @param array $json
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function constructCheckboxMultiButton(array $formElement, $htmlFormElementName, $attributeBase, $value, array $itemKey, array $itemValue, array &$json) {
         $json = array();
@@ -1842,6 +1898,8 @@ abstract class AbstractBuildForm {
      * @param array $json
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function constructCheckboxMultiPlain(array $formElement, $htmlFormElementName, $attributeBase, $value, array $itemKey, array $itemValue, array &$json) {
         $json = array();
@@ -1930,6 +1988,8 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function buildExtra(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
 
@@ -1954,6 +2014,8 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function buildRadio(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
 
@@ -2000,6 +2062,8 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     private function constructRadioButton(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
         $itemKey = array();
@@ -2081,6 +2145,8 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     private function constructRadioPlain(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
         $attributeBase = '';
@@ -2169,6 +2235,8 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return mixed
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function buildSelect(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
         $itemKey = array();
@@ -2274,6 +2342,8 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function buildSubrecord(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
         $rcText = false;
@@ -2431,6 +2501,8 @@ abstract class AbstractBuildForm {
      * @param $toolTip
      * @param array $currentRow
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     private function createFormLink(array $formElement, $targetRecordId, array $record, $symbol, $toolTip, $currentRow = array()) {
 
@@ -2498,6 +2570,9 @@ abstract class AbstractBuildForm {
      * @param string $formName
      *
      * @return string   tableName for $formName
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
      */
     private function getFormTable($formName) {
         $row = $this->dbArray[$this->dbIndexQfq]->sql("SELECT " . F_TABLE_NAME . " FROM Form AS f WHERE f.name = ?", ROW_EXPECT_0_1, [$formName]);
@@ -2528,6 +2603,7 @@ abstract class AbstractBuildForm {
      * @param array $titleRaw
      *
      * @return array
+     * @throws UserFormException
      */
     private function getSubrecordColumnControl(array $titleRaw) {
         $control = array();
@@ -2605,6 +2681,9 @@ abstract class AbstractBuildForm {
      * @param string $columnValue
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
+     * @throws UserReportException
      */
     private function renderCell(array $control, $columnName, $columnValue) {
         $link = null;
@@ -2667,6 +2746,8 @@ abstract class AbstractBuildForm {
      *                          parameters.
      *
      * @return string String: "API_DIR/delete.php?sip=...."
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function createDeleteUrl($formName, $recordId, $mode = RETURN_URL) {
 
@@ -2694,7 +2775,10 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return string
+     * @throws CodeException
+     * @throws DbException
      * @throws UserFormException
+     * @throws UserReportException
      */
     public function buildFile(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
         $attribute = '';
@@ -2811,6 +2895,7 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return string
+     * @throws CodeException
      * @throws UserFormException
      */
     public function buildAnnotate(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
@@ -2863,6 +2948,7 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return string
+     * @throws CodeException
      * @throws UserFormException
      */
     public function buildImageCut(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
@@ -2930,6 +3016,8 @@ abstract class AbstractBuildForm {
     /**
      * @param string $pathFileName
      * @return string SIP encoded URL
+     * @throws CodeException
+     * @throws UserFormException
      */
     private function fileToSipUrl($pathFileName) {
         $param[DOWNLOAD_MODE] = DOWNLOAD_MODE_FILE;
@@ -2953,6 +3041,7 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return string
+     * @throws CodeException
      * @throws UserFormException
      */
     public function buildDateTime(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
@@ -3065,6 +3154,8 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function buildDateJQW(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
         $arrMinMax = null;
@@ -3147,6 +3238,8 @@ abstract class AbstractBuildForm {
      * @param string $mode
      *
      * @return string
+     * @throws CodeException
+     * @throws UserFormException
      */
     public function buildEditor(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
         $attribute = '';
@@ -3297,6 +3390,7 @@ abstract class AbstractBuildForm {
      *
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      * @return mixed
+     * @throws CodeException
      */
     public function buildNote(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
 
@@ -3331,6 +3425,10 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return mixed
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
+     * @throws UserReportException
      */
     public function buildFieldset(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
         $attribute = '';
@@ -3397,6 +3495,10 @@ abstract class AbstractBuildForm {
      * @param string $mode FORM_LOAD | FORM_UPDATE | FORM_SAVE
      *
      * @return mixed
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
+     * @throws UserReportException
      */
     public function buildTemplateGroup(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
         $attribute = '';
@@ -3509,6 +3611,10 @@ EOT;
      * @param array $json
      *
      * @return string
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
+     * @throws UserReportException
      */
     private function templateGroupCollectFilledElements($max, $htmlDelete, array &$json) {
 
@@ -3591,6 +3697,10 @@ EOT;
      * Additional the maximum count of all select rows will be determined and returned.
      *
      * @return int   max number of records in FormElement[FE_VALUE] over all FormElements.
+     * @throws CodeException
+     * @throws DbException
+     * @throws UserFormException
+     * @throws UserReportException
      */
     private function templateGroupDoValue() {
 
diff --git a/extension/qfq/qfq/Constants.php b/extension/qfq/qfq/Constants.php
index b7d84ed49..fdd375074 100644
--- a/extension/qfq/qfq/Constants.php
+++ b/extension/qfq/qfq/Constants.php
@@ -143,7 +143,7 @@ const ERROR_DEBUG = 1031;
 const ERROR_UNKNOWN_MODE = 1032;
 const ERROR_NOT_IMPLEMENTED = 1033;
 const ERROR_RESERVED_KEY_NAME = 1034;
-
+const ERROR_MISSING_PARAMETER_FILE = 1035;
 const ERROR_UNKNOWN_FORWARD_MODE = 1036;
 
 const ERROR_MISSING_HIDDEN_FIELD_IN_SIP = 1038;
@@ -1246,6 +1246,7 @@ const COLUMN_PAGES = 'pages';
 const COLUMN_PDF = 'pdf';
 const COLUMN_FILE = 'file';
 const COLUMN_ZIP = 'zip';
+const COLUMN_MONITOR = 'monitor';
 
 const COLUMN_NL2BR = 'nl2br';
 const COLUMN_HTMLENTITIES = 'htmlentities';
@@ -1266,6 +1267,7 @@ const DOWNLOAD_MODE_PDF = 'pdf';
 const DOWNLOAD_MODE_EXCEL = 'excel';
 const DOWNLOAD_MODE_ZIP = 'zip';
 const DOWNLOAD_MODE_THUMBNAIL = 'thumbnail';
+const DOWNLOAD_MODE_MONITOR = 'monitor';
 const DOWNLOAD_EXPORT_FILENAME = '_exportFilename';
 const TMP_FILE_PREFIX = 'qfq.temp.'; // temporary filename on server of single export file
 const DOWNLOAD_OUTPUT_FILENAME = 'output';
@@ -1328,6 +1330,13 @@ const TOKEN_CLASS_NONE = 'n';
 //const TOKEN_CLASS_INTERNAL = 'i';
 //const TOKEN_CLASS_EXTERNAL = 'e';
 
+const TOKEN_L_FILE = 'file';
+const TOKEN_L_TAIL = 'tail';
+const TOKEN_L_APPEND = 'append';
+const TOKEN_L_INTERVAL = 'interval';
+const TOKEN_L_HTML_ID = 'htmlId';
+
+
 const RENDER_MODE_1 = '1';
 const RENDER_MODE_2 = '2';
 const RENDER_MODE_3 = '3';
diff --git a/extension/qfq/qfq/QuickFormQuery.php b/extension/qfq/qfq/QuickFormQuery.php
index 0f2cb03d5..f16ce9182 100644
--- a/extension/qfq/qfq/QuickFormQuery.php
+++ b/extension/qfq/qfq/QuickFormQuery.php
@@ -1342,6 +1342,4 @@ EOF;
 
         return $code;
     }
-
-
 }
\ No newline at end of file
diff --git a/extension/qfq/qfq/helper/Support.php b/extension/qfq/qfq/helper/Support.php
index ca924704f..d122ab7c2 100644
--- a/extension/qfq/qfq/helper/Support.php
+++ b/extension/qfq/qfq/helper/Support.php
@@ -1093,7 +1093,7 @@ class Support {
     }
 
     /**
-     * Looks in $arr if there is an element $index. If not, set it to $value.
+     * Check $arr, if there is an element $index. If not, set it to $value.
      * If  $overwriteThis!=false, replace the the original value with $value, if $arr[$index]==$overwriteThis.
      *
      * @param array $arr
diff --git a/extension/qfq/qfq/report/Download.php b/extension/qfq/qfq/report/Download.php
index 6d63a5928..83295de42 100644
--- a/extension/qfq/qfq/report/Download.php
+++ b/extension/qfq/qfq/report/Download.php
@@ -69,6 +69,7 @@ class Download {
     /**
      * @param bool|false $phpUnit
      * @throws CodeException
+     * @throws DbException
      * @throws UserFormException
      */
     public function __construct($phpUnit = false) {
@@ -260,7 +261,7 @@ class Download {
 
     /**
      * exportFilename=<new filename>
-     * mode=file | pdf | excel - default is 'file' in case of only one or 'pdf' in case of multiple sources.
+     * mode=file | pdf | excel | thumbnail | monitor - default is 'file' in case of only one or 'pdf' in case of multiple sources.
      * HTML to PDF | Excel
      *   <i>_id=<Typo3 pageId>
      *   <i>_<key>=<value i>
@@ -287,6 +288,11 @@ class Download {
 
         $downloadMode = $vars[DOWNLOAD_MODE];
 
+        if($downloadMode == DOWNLOAD_MODE_MONITOR){
+            $monitor = new Monitor();
+            return $monitor->tailCustom($vars[TOKEN_L_FILE], $vars[TOKEN_L_TAIL]);
+        }
+
         if ($downloadMode == DOWNLOAD_MODE_THUMBNAIL) {
             // Fake $vars control array.
             $pathFilenameThumbnail = $this->doThumbnail($vars[SIP_DOWNLOAD_PARAMETER]);
diff --git a/extension/qfq/qfq/report/Link.php b/extension/qfq/qfq/report/Link.php
index 6e3a6990c..923445bd9 100644
--- a/extension/qfq/qfq/report/Link.php
+++ b/extension/qfq/qfq/report/Link.php
@@ -827,6 +827,7 @@ class Link {
             if ($vars[NAME_SIP] === "1") {
 
                 $paramArray = $this->sip->queryStringToSip($urlNParam, RETURN_ARRAY);
+                //TODO: Index '_url' umbnennen
                 $urlNParam = $paramArray['_url'];
 
                 if (Support::findInSet(SYSTEM_SHOW_DEBUG_INFO_YES, $this->store->getVar(SYSTEM_SHOW_DEBUG_INFO, STORE_SYSTEM))) {
@@ -1652,4 +1653,5 @@ EOF;
 
         return $vars;
     }
+
 }
\ No newline at end of file
diff --git a/extension/qfq/qfq/report/Monitor.php b/extension/qfq/qfq/report/Monitor.php
new file mode 100644
index 000000000..ccdfa783b
--- /dev/null
+++ b/extension/qfq/qfq/report/Monitor.php
@@ -0,0 +1,149 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: crose
+ * Date: 2/10/18
+ * Time: 3:14 PM
+ *
+ * See: doc/THUMBNAIL.md
+ */
+
+namespace qfq;
+
+require_once(__DIR__ . '/../store/Store.php');
+require_once(__DIR__ . '/../helper/Support.php');
+require_once(__DIR__ . '/../helper/Token.php');
+require_once(__DIR__ . '/../helper/OnString.php');
+
+//use qfq;
+
+/**
+ * Class Thumbnail
+ * @package qfq
+ */
+class Monitor {
+
+    /**
+     * @var Store
+     */
+    private $store = null;
+
+    /**
+     * @param bool|false $phpUnit
+     * @throws CodeException
+     * @throws UserFormException
+     */
+    public function __construct($phpUnit = false) {
+        $this->store = Store::getInstance();
+    }
+
+    /**
+     * Renders some JS to monitor a file on the server.
+     * $str: 'file:typo3conf/sql.log|tail:1000|append:1|interval:1000|htmlId:monitor1'
+     *
+     * @param string $str
+     *
+     * @return string
+     * @throws CodeException
+     * @throws UserFormException
+     * @throws UserReportException
+     */
+    public function process($str) {
+
+        // Decode: 'file:typo3conf/sql.log|tail:1000|append:1|interval:1000|htmlId:monitor1' AS _monitor
+        $control = Token::explodeTokenString($str);
+
+        if (empty($control[TOKEN_L_FILE])) {
+            throw new UserReportException("Monitor: empty or missing parameter 'file'", ERROR_MISSING_PARAMETER_FILE);
+        }
+
+        // Set defaults
+        Support::setIfNotSet($control, TOKEN_L_TAIL, 1000);
+        $isContinuous = Support::setIfNotSet($control, TOKEN_L_APPEND, '1') == '1' ? 'true' : 'false';
+        $interval = Support::setIfNotSet($control, TOKEN_L_INTERVAL, 100);
+        $htmlId = Support::setIfNotSet($control, TOKEN_L_HTML_ID, 'monitor1');
+
+        // Setup query to generate SIP
+        $queryString = DOWNLOAD_MODE . '=' .  DOWNLOAD_MODE_MONITOR . '&' . TOKEN_L_FILE . '=' . $control[TOKEN_L_FILE] . '&' . TOKEN_L_TAIL . '=' . $control[TOKEN_L_TAIL];
+        $url = store::getSipInstance()->queryStringToSip(API_DIR . '/' . API_DOWNLOAD_PHP . '?' . $queryString, RETURN_URL);
+
+        $code = <<<EOF
+<script type="text/javascript">
+    $(document).ready(function () {
+        var getFile = new QfqNS.DisplayFile({
+            webworker: "Worker/GetFileContent.js",
+            filePath: "$url",
+            interval: $interval,
+            targetId: "$htmlId",
+            isContinuous: $isContinuous
+        });
+        getFile.show();
+    });
+</script>
+EOF;
+
+        return $code;
+    }
+
+    /**
+     * Slightly modified version of http://www.geekality.net/2011/05/28/php-tail-tackling-large-files/
+     * @author Torleif Berger, Lorenzo Stanco
+     * @link http://stackoverflow.com/a/15025877/995958
+     * @license http://creativecommons.org/licenses/by/3.0/
+     */
+    public function tailCustom($filepath, $lines = 1, $adaptive = true) {
+
+        // Open file
+        $f = @fopen($filepath, "rb");
+        if ($f === false) return false;
+
+        // Sets buffer size, according to the number of lines to retrieve.
+        // This gives a performance boost when reading a few lines from the file.
+        if (!$adaptive) $buffer = 4096;
+        else $buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096));
+
+        // Jump to last character
+        fseek($f, -1, SEEK_END);
+
+        // Read it and adjust line number if necessary
+        // (Otherwise the result would be wrong if file doesn't end with a blank line)
+        if (fread($f, 1) != "\n") $lines -= 1;
+
+        // Start reading
+        $output = '';
+        $chunk = '';
+
+        // While we would like more
+        while (ftell($f) > 0 && $lines >= 0) {
+
+            // Figure out how far back we should jump
+            $seek = min(ftell($f), $buffer);
+
+            // Do the jump (backwards, relative to where we are)
+            fseek($f, -$seek, SEEK_CUR);
+
+            // Read a chunk and prepend it to our output
+            $output = ($chunk = fread($f, $seek)) . $output;
+
+            // Jump back to where we started reading
+            fseek($f, -mb_strlen($chunk, '8bit'), SEEK_CUR);
+
+            // Decrease our line counter
+            $lines -= substr_count($chunk, "\n");
+
+        }
+
+        // While we have too many lines
+        // (Because of buffer size we might have read too many)
+        while ($lines++ < 0) {
+
+            // Find first newline and remove all text before that
+            $output = substr($output, strpos($output, "\n") + 1);
+
+        }
+
+        // Close file and return
+        fclose($f);
+        return trim($output);
+    }
+}
\ No newline at end of file
diff --git a/extension/qfq/qfq/report/Report.php b/extension/qfq/qfq/report/Report.php
index 6c44a55ce..606758e50 100644
--- a/extension/qfq/qfq/report/Report.php
+++ b/extension/qfq/qfq/report/Report.php
@@ -89,11 +89,17 @@ class Report {
     private $db = null;
 
     private $dbIndexData = false;
+
     /**
      * @var Thumbnail
      */
     private $thumbnail = null;
 
+    /**
+     * @var Monitor
+     */
+    private $monitor = null;
+
     /**
      * @var array
      */
@@ -118,6 +124,7 @@ class Report {
      * @param Evaluate $eval
      * @param bool $phpUnit
      * @throws CodeException
+     * @throws DbException
      * @throws UserFormException
      */
     public function __construct(array $t3data, Evaluate $eval, $phpUnit = false) {
@@ -614,6 +621,7 @@ class Report {
      * @return string               Collected content of all printable columns
      * @throws CodeException
      * @throws DbException
+     * @throws DownloadException
      * @throws UserFormException
      * @throws UserReportException
      */
@@ -668,6 +676,7 @@ class Report {
      * @return string rendered column
      * @throws CodeException
      * @throws DbException
+     * @throws DownloadException
      * @throws UserFormException
      * @throws UserReportException
      */
@@ -709,10 +718,10 @@ class Report {
             case COLUMN_PPAGEI:
             case COLUMN_PPAGEN:
             case COLUMN_PPAGES:
-            $lowerColumnName = strtolower($columnName);
+                $lowerColumnName = strtolower($columnName);
                 $tokenizedValue = $this->doFixColPosPage($columnName, $columnValue);
-            $linkValue = $this->doPage($lowerColumnName, $tokenizedValue);
-            $content .= $this->link->renderLink($linkValue);
+                $linkValue = $this->doPage($lowerColumnName, $tokenizedValue);
+                $content .= $this->link->renderLink($linkValue);
                 break;
 
             // Lowercase 'P'
@@ -725,7 +734,7 @@ class Report {
             case COLUMN_PAGEN:
             case COLUMN_PAGES:
                 $linkValue = $this->doPage($columnName, $columnValue);
-            $content .= $this->link->renderLink($linkValue);
+                $content .= $this->link->renderLink($linkValue);
                 break;
 
             case COLUMN_PPDF:
@@ -751,6 +760,13 @@ class Report {
                 $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;
@@ -908,17 +924,6 @@ class Report {
         return $content;
     }
 
-    /**
-     * 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
-
     /**
      * Renders PageX: convert position content to token content. Respect default values depending on PageX
      *
@@ -1151,11 +1156,6 @@ class Report {
             $columnValue .= $defaultBootstrapButton . "|";
         }
 
-
-//        if ($columnName === 'paged') {
-//            $columnValue = $this->adjustDeleteParameter($columnValue);
-//        }
-
         return ($columnValue);
     }
 
diff --git a/extension/qfq/qfq/report/Thumbnail.php b/extension/qfq/qfq/report/Thumbnail.php
index 69be01450..1867686ac 100644
--- a/extension/qfq/qfq/report/Thumbnail.php
+++ b/extension/qfq/qfq/report/Thumbnail.php
@@ -10,6 +10,7 @@
 
 namespace qfq;
 
+require_once(__DIR__ . '/../store/Store.php');
 require_once(__DIR__ . '/../helper/Support.php');
 require_once(__DIR__ . '/../helper/Token.php');
 require_once(__DIR__ . '/../helper/OnString.php');
diff --git a/extension/qfq/qfq/store/Sip.php b/extension/qfq/qfq/store/Sip.php
index 3a6e05698..949cfc7eb 100644
--- a/extension/qfq/qfq/store/Sip.php
+++ b/extension/qfq/qfq/store/Sip.php
@@ -41,7 +41,6 @@ class Sip {
      *                            * index.php?a=1&s=4b3403665fea6&r=45&type=99&id=person#pill12
      *                            * ?a=1&s=4b3403665fea6&r=45&type=99&id=person#pill12
      *                            * a=1&s=4b3403665fea6&r=45&type=99&id=person#pill12
-     *                            * a=1&s=4b3403665fea6&r=45&type=99&id=person#pill12
      *
      * @param string $mode Possible values: RETURN_URL|RETURN_SIP
      *
-- 
GitLab