From de14d11e4ec003fa629a5dec9287fb785326c73c Mon Sep 17 00:00:00 2001 From: Carsten Rose <carsten.rose@math.uzh.ch> Date: Sat, 16 Jun 2018 17:29:45 +0200 Subject: [PATCH] F5885: implement 'append' mode. --- doc/PROTOCOL.md | 65 ++- extension/Documentation/Manual.rst | 608 +++++++++++++----------- extension/qfq/api/download.php | 24 +- extension/qfq/qfq/AbstractBuildForm.php | 2 +- extension/qfq/qfq/Constants.php | 12 +- extension/qfq/qfq/report/Download.php | 6 +- extension/qfq/qfq/report/Link.php | 3 +- extension/qfq/qfq/report/Monitor.php | 118 ++++- extension/qfq/qfq/report/Report.php | 1 + extension/qfq/qfq/store/Sip.php | 6 +- 10 files changed, 510 insertions(+), 335 deletions(-) diff --git a/doc/PROTOCOL.md b/doc/PROTOCOL.md index 0e8157dd0..0b48c3a2c 100644 --- a/doc/PROTOCOL.md +++ b/doc/PROTOCOL.md @@ -399,40 +399,59 @@ A download might be: * a converted HTML page to PDF, * a PDF file, concatenated on single PDF files and/or converted HTML page to PDF. * a thumbnail, streamed from cache dir of if not present/recent rendered on request. + * a file to monitor constantly. 'api/download.php' will be called with a SIP (no other vars used). The SIP contains: * DOWNLOAD_EXPORT_FILENAME - any target filename, if none given take DOWNLOAD_OUTPUT_PDF ('output.pdf'). - * DONWLOAD_MODE - file / pdf / excel / zip / thumbnail. If not specified: + * DONWLOAD_MODE - file / pdf / excel / zip / thumbnail / monitor. If not specified: a) 'file' is the default, if only one source is given and if that is a file. b) 'pdf' is the default, if there are multiple TOKEN_URL, TOKEN_URL_PARAM, TOKEN_FILE in SIP_DOWNLOAD_PARAMETER found. - * SIP_DOWNLOAD_PARAMETER (base64 encoded): all DONWLOAD_MODE but 'thumbnail' - contains all parameter to source elements. - Format: <format 1>:<element 1>|<format 2>:<element 2>|...|<format n>:<element n>| - - <format>: TOKEN_URL, TOKEN_URL_PARAM, TOKEN_FILE, TOKEN_THUMBNAIL_DIMENSION - <element>: depending on the token - see below - - URL: a) 'u:http://w3c.org', b) 'u:w3c.org/', c) 'u:w3c.org/2017/index.php?issue=23' - URL_PARAM: a) 'U:id=export&r=123', b) 'U:id=export&r=123&_orientation=landscape&_page-size=a3' - FILE: a) 'F:fileadmin/example.png' + * DONWLOAD_MODE: file / pdf / excel / zip + + * SIP_DOWNLOAD_PARAMETER (base64 encoded) - contains all parameter to source elements. + + Format: <format 1>:<element 1>|<format 2>:<element 2>|...|<format n>:<element n>| + + <format>: TOKEN_URL, TOKEN_URL_PARAM, TOKEN_FILE, TOKEN_THUMBNAIL_DIMENSION + <element>: depending on the token - see below + + URL: a) 'u:http://w3c.org', b) 'u:w3c.org/', c) 'u:w3c.org/2017/index.php?issue=23' + URL_PARAM: a) 'U:id=export&r=123', b) 'U:id=export&r=123&_orientation=landscape&_page-size=a3' + FILE: a) 'F:fileadmin/example.png' + + * In URL_PARAM extra parameter used by `wkhtmltopdf` can be specified. All Parameter, starting with '-' + will be extracted from the regular URL_PARAM and instead forwarded as options to `wkhtmlpdf` + + * DONWLOAD_MODE: thumbnail + + * SIP_DOWNLOAD_PARAMETER (base64 encoded) + + * T:<pathFilename Source> + * W:<dimension> + * r:<render mode> + * Render the thumbnail + + Download.php will be called with the SIP. After decoding the SIP, the base64 encoded parameter are used with + DONWLOAD_MODE=file and SIP_DOWNLOAD_PARAMETER=F:<thumbnail> + + * DONWLOAD_MODE: monitor + + SIP encoded parameter - * In URL_PARAM extra parameter used by `wkhtmltopdf` can be specified. All Parameter, starting with '-' - will be extracted from the regular URL_PARAM and instead forwarded as options to `wkhtmlpdf` - - * SIP_DOWNLOAD_PARAMETER (base64 encoded): *DONWLOAD_MODE:thumbnail* - * T:<pathFilename Source> - * W:<dimension> - * r:<render mode> - * Render the thumbnail - Download.php will be called with the SIP. After decoding the SIP, the base64 encoded parameter are used with - DONWLOAD_MODE=file and SIP_DOWNLOAD_PARAMETER=F:<thumbnail> - + * file: <filename> + * tail: <number of last lines> + * append: 0|1 + + The retrieved lines are outputted without any conversion. + * The base64 encoding is necessary: + * to deliver multiple elements with the same token (e.g. multiple PDF files to concatenate). * special parameter names, like 'id', should not force the regular interpretation of 'id' during conversion to a SIP. -During preparing and delivering the download, a popup shows a spinning gear by default. The popup itself will display an -individual message. The popup needs some HTML code (only once per T3 page). +During preparing and delivering the download ()file / pdf / excel / zip), a popup shows a spinning gear by default. The +popup itself will display an individual message. The popup needs some HTML code (only once per T3 page). Download links might be generated in `report` as well as in `subrecords of forms`. To trigger the generation of the HTML popup code, a variable DOWNLOAD_POPUP_REQUEST in STORE_SYSTEM will be set to 'true' (string) in class Link(), as soon as the first download link is rendered. During internal rendering of the download link, the const text token diff --git a/extension/Documentation/Manual.rst b/extension/Documentation/Manual.rst index a8bb18561..f696bec61 100644 --- a/extension/Documentation/Manual.rst +++ b/extension/Documentation/Manual.rst @@ -5099,6 +5099,8 @@ Special column names +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _thumbnail |Create thumbnails on the fly. See `column-thumbnail`_. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| _monitor |Constantly display a file. See `column-monitor`_. | ++------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _+??? |The content will be wrapped in the tag '???'. Example: SELECT 'example' AS '_+a href="http://example.com"' creates '<a href="http://example.com">example</a>' | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |_<nonReservedName> |Suppress output. Column names with leading underscore are used to select data from the database and make it available in other parts of the report without generating any output. | @@ -5314,250 +5316,6 @@ Examples: | SELECT "p:form_person|q:Edit Person:::10:0" AS _link | The Alert will be shown 10 seconds and is not modal. | +------------------------------------------------------------+---------------------------------------------------------------------------+ -.. _download: - -Download -^^^^^^^^ - -Download offers: - -* download a single file (any type), -* concatenate several files (uploaded) and/or web pages (=HTML to PDF) into one PDF output file, -* create a ZIP archive, filled with several files ('uploaded' or 'HTML to PDF'-converted). - -The downloads are SIP protected. Only the current user can use the link to download files. - -By using the `_link` columnname: - -* the option `d:...` initiate creating the download link and optional specifies an export filename, -* the optional `M:...` (Mode) specifies the export type (file, pdf, zip), -* setting `s:1` is mandatory for the download function, -* the alttext `a:...` specifies a message in the download popup. - -By using `_pdf`, `_Pdf`, `_file`, `_File`, `_zip`, `_Zip` as columnname, the options `d`, `m` and `s` -will be set by automatically. - -All files will be read by PHP - therefore the directory might be protected against direct web access. This way is the -preferred way to offer secure downloads via QFQ. - -In case the download needs a persistant URL (no SIP, no user session), a regular -link, pointing directly to a file, have to be used - the download functionality described here is not appropriate for -such a scenario. - -.. _download-parameter-files: - -Parameter and (element) sources -''''''''''''''''''''''''''''''' - -* *download*: `d[:<exportFilename>]` - - * *exportFilename* = <filename for save as> - Name, offered in the 'File save as' browser dialog. Default: 'output.<ext>'. - - If there is no `exportFilename` defined, then the original filename is taken. - - The user typically expects meaningful and distinct filenames for different download links. - -* *popupMessage*: `a:<text>` - will be displayed in the popup window during download. If the creating/download is fast, the window might disappear quickly. - -* *mode*: `M:<mode>` - - * *mode* = <file | pdf | zip> - This parameter is optional and can be skipped in most situations. Mandatory - for 'zip'. - - * If `M:file`, the mime type is derived dynamically from the specified file. In this mode, only one element source - is allowed per download link (no concatenation). - - * In case of multiple element sources, only `pdf` or `zip` is supported. - * If `M:zip` is used together with `p:...`, `U:...` or `u:..`, those HTML pages will be converted to PDF. Those files - get generic filenames inside the archive. - * If not specified, the **default** 'Mode' depends on the number of specified element sources (=file or web page): - - * If only one `file` is specifed, the default is `file`. - * If there is a) a page defined or b) multiple elements, the default is `pdf`. - -* *element sources* - for `M:pdf` or `M:zip`, all of the following three element sources might be specified multiple times. Any combination and order of the three options are allowed. - - * *file*: `F:<pathFileName>` - relative or absolute pathFileName offered for a) download (single), or to be concatenated - in a PDF or ZIP. - * *page*: `p:id=<t3 page>&<key 1>=<value 1>&<key 2>=<value 2>&...&<key n>=<value n>`. - - * By default, the options given to wkhtml will *not* be encoded by a SIP! - * To encode the parameter via SIP: Add '_sip=1' to the URL GET parameter. - - E.g. `p:id=form&_sip=1&form=Person&r=1`. - - In that way, specific sources for the `download` might be SIP encrypted. - - * Any current HTML cookies will be forwarded to/via `wkhtml`. This includes the current FE Login as well as any - QFQ session. Also the current User-Agent are faked via the `wkhtml` page request. - - * If there are trouble with accessing FE_GROUP protected content, please check `wkhtmltopdf`_. - - * *url*: `u:<url>` - any URL, pointing to an internal or external destination. - - * *WKHTML Options* for `page`, `urlParam` or `url`: - - * The 'HTML to PDF' will be done via `wkhtmltopdf`. - * All possible options, suitable for `wkhtmltopdf`, can be submitted in the `p:...`, `u:...` or `U:...` element source. - Check `wkhtmltopdf.txt <https://wkhtmltopdf.org/usage/wkhtmltopdf.txt>`_ for possible options. Be aware that - key/value tuple in the documentation is separated by a space, but to respect the QFQ key/value notation of URLs, - the key/value tuple in `p:...`, `u:...` or `U:...` has to be separated by '='. Please see last example below. - - Most of the other Link-Class attributes can be used to customize the link as well. - -Example `_link`: :: - - # single `file`. Specifying a popup message window text is not necessary, cause a file directly accessed is fast. - SELECT "d:file.pdf|s|t:Download|F:fileadmin/pdf/test.pdf" AS _link - - # single `file`, with mode - SELECT "d:file.pdf|M:pdf|s|t:Download|F:fileadmin/pdf/test.pdf" AS _link - - # three sources: two pages and one file - SELECT "d:complete.pdf|s|t:Complete PDF|p:id=detail&r=1|p:id=detail2&r=1|F:fileadmin/pdf/test.pdf" AS _link - - # three sources: two pages and one file - SELECT "d:complete.pdf|s|t:Complete PDF|p:id=detail&r=1|p:id=detail2&r=1|F:fileadmin/pdf/test.pdf" AS _link - - # three sources: two pages and one file, parameter to wkhtml will be SIP encoded - SELECT "d:complete.pdf|s|t:Complete PDF|p:id=detail&r=1&_sip=1|p:id=detail2&r=1&_sip=1|F:fileadmin/pdf/test.pdf" AS _link - - # three sources: two pages and one file, the second page will be in landscape and pagesize A3 - SELECT "d:complete.pdf|s|t:Complete PDF|p:id=detail&r=1|p:id=detail2&r=1&--orientation=Landscape&--page-size=A3|F:fileadmin/pdf/test.pdf" AS _link - -.. - -Example `_pdf`, `_zip`: :: - - # File 1: p:id=1&--orientation=Landscape&--page-size=A3 - # File 2: p:id=form - # File 3: F:fileadmin/file.pdf - SELECT 't:PDF|a:Creating a new PDF|p:id=1&--orientation=Landscape&--page-size=A3|p:id=form|F:fileadmin/file.pdf' AS _pdf - - # File 1: p:id=1 - # File 2: u:http://www.example.com - # File 3: F:fileadmin/file.pdf - SELECT 't:PDF - 3 Files|a:Please be patient|p:id=1|u:http://www.example.com|F:fileadmin/file.pdf' AS _pdf - - # File 1: p:id=1 - # File 2: p:id=form - # File 3: F:fileadmin/file.pdf - SELECT CONCAT('t:ZIP - 3 Pages|a:Please be patient|p:id=1|p:id=form|F:', p.pathFileName) AS _zip - -.. - -Use the `--print-media-type` as wkhtml option to access the page with media type 'printer'. Depending on the website -configuration this switches off navigation and background images. - -Rendering PDF letters -''''''''''''''''''''' - -`wkhtmltopdf`, with the header and footer options, can be used to render multi page PDF letters (repeating header, -pagination) in combination with dynamic content. Such PDFs might look-alike official letters, together with logo and signature. - -Best practice: - -#. Create a clean (=no menu, no website layout) letter layout in a separated T3 branch: :: - - page = PAGE - page.typeNum = 0 - page.includeCSS { - 10 = typo3conf/ext/qfq/Resources/Public/Css/qfq-letter.css - } - - // Grant access to any logged in user or specific development IPs - [usergroup = *] || [IP = 127.0.0.1,192.168.1.* ] - page.10 < styles.content.get - [else] - page.10 = TEXT - page.10.value = access forbidden - [global] - -#. Create a T3 `body` page (e.g. page alias: 'letterbody') with some content. Example static HTML content: :: - - <div class="letter-receiver"> - <p>Address</p> - </div> - <div class="letter-sender"> - <p><b>firstName name</b><br> - Phone +00 00 000 00 00<br> - Fax +00 00 000 00 00<br> - </p> - </div> - - <div class="letter-date"> - Zurich, 01.12.2017 - </div> - - <div class="letter-body"> - <h1>Subject</h1> - - <p>Dear Mrs...</p> - <p>Lucas ipsum dolor sit amet organa solo skywalker darth c-3p0 anakin jabba mara greedo skywalker.</p> - - <div class="letter-no-break"> - <p>Regards</p> - <p>Company</p> - <img class="letter-signature" src=""> - <p>Firstname Name<br>Function</p> - </div> - </div> - -#. Create a T3 letter-`header` page (e.g. page alias: 'letterheader') , with only the header information: :: - - <header> - <img src="fileadmin/logo.png" class="letter-logo"> - - <div class="letter-unit"> - <p class="letter-title">Department</p> - <p> - Company name<br> - Company department<br> - Street<br> - City - </p> - </div> - </header> - -#. Create a) a link (Report) to the PDF letter or b) attach the PDF (on the fly rendered) to a mail. Both will call the - `wkhtml` via the `download` mode and forwards the necessary parameter. - -Use in `report`: :: - - sql = SELECT CONCAT('d:Letter.pdf|t:',p.firstName, ' ', p.name, - '|p:id=letterbody&pId=', p.id, '&_sip=1&--margin-top=50mm&--margin-bottom=20mm&', - '--header-html={{BASE_URL_PRINT:Y}}?id=letterheader&', - '--footer-right="Seite: [page]/[toPage]"&', - '--footer-font-size=8&--footer-spacing=10') AS _pdf - FROM Person AS p ORDER BY p.id - - -Sendmail. Parameter: :: - - sendMailAttachment={{SELECT 'd:Letter.pdf|t:', p.firstName, ' ', p.name, '|p:id=letterbody&pId=', p.id, '&_sip=1&--margin-top=50mm&--margin-bottom=20mm&--header-html={{BASE_URL_PRINT:Y}}?id=letterheader&--footer-right="Seite: [page]/[toPage]"&--footer-font-size=8&--footer-spacing=10' FROM Person AS p WHERE p.id={{id:S}} }} - -Replace the static content elements from 2. and 3. by QFQ Content elements as needed: :: - - 10.sql = SELECT '<div class="letter-receiver"><p>', p.name AS '_+br', p.street AS '_+br', p.city AS '_+br', '</p>' - FROM Person AS p WHERE p.id={{pId:S}} - - -Export area -''''''''''' - -To offer protected pages, e.g. referenced in download links, the regular FE_GROUPs can't be used, cause the download does -not have the current user privileges (it's a separate process, started as the webserver user). - -Create a separated export tree in Typo3 Backend, which is IP access restricted. Only localhost or the FE_GROUP 'admin' -is allowed to access: :: - - [IP = {$tmp.restrictedIPRange} ][usergroup = admin] - page.10 < styles.content.get - [else] - page.10 = TEXT - page.10.value = Please access from localhost or log in as 'admin' user. - [global] - .. _column_pageX: Columns: _page[X] @@ -5570,7 +5328,7 @@ The colum name is composed of the string *page* and a trailing character to spec :: - SELECT "[options]" AS _page[<link type>] + 10.sql = SELECT "[options]" AS _page[<link type>] with: [options] = [p:<page & param>][|t:<text>][|o:<tooltip>][|q:<question parameter>][|c:<class>][|g:<target>][|r:<render mode>] @@ -5638,8 +5396,8 @@ These column offers a link, with a confirmation question, to delete one record ( :: - SELECT "U:table=<tablename>&r=<record id>|q:<question>|..." AS _paged - SELECT "U:form=<formname>&r=<record id>|q:<question>|..." AS _paged + 10.sql = SELECT "U:table=<tablename>&r=<record id>|q:<question>|..." AS _paged + 10.sql = SELECT "U:form=<formname>&r=<record id>|q:<question>|..." AS _paged .. @@ -5670,8 +5428,8 @@ Examples: :: - SELECT 'U:table=Person&r=123|q:Do you want delete John Doe?' AS _paged - SELECT 'U:form=person-main&r=123|q:Do you want delete John Doe?' AS _paged + 10.sql = SELECT 'U:table=Person&r=123|q:Do you want delete John Doe?' AS _paged + 10.sql = SELECT 'U:form=person-main&r=123|q:Do you want delete John Doe?' AS _paged .. _column_ppageX: @@ -5710,7 +5468,7 @@ angle. :: - SELECT "<text>|[<angle>]|[<width>]|[<height>]|[<wrap tag>]" AS _vertical + 10.sql = SELECT "<text>|[<angle>]|[<width>]|[<height>]|[<wrap tag>]" AS _vertical .. @@ -5762,7 +5520,7 @@ Easily create Email links. :: - SELECT "<email address>|[<link text>]" AS _mailto + 10.sql = SELECT "<email address>|[<link text>]" AS _mailto .. @@ -5826,8 +5584,8 @@ Send emails. Every mail will be logged in the table `mailLog`. Attachments are s :: - SELECT "t:john@doe.com|f:jane@doe.com|s:Reminder tomorrow|b:Please dont miss the meeting tomorrow" AS _sendmail - SELECT "t:john@doe.com|f:jane@doe.com|s:Reminder tomorrow|b:Please dont miss the meeting tomorrow|A:off|g:1|x:2|y:3|z:4" AS _sendmail + 10.sql = SELECT "t:john@doe.com|f:jane@doe.com|s:Reminder tomorrow|b:Please dont miss the meeting tomorrow" AS _sendmail + 10.sql = SELECT "t:john@doe.com|f:jane@doe.com|s:Reminder tomorrow|b:Please dont miss the meeting tomorrow|A:off|g:1|x:2|y:3|z:4" AS _sendmail .. @@ -5989,7 +5747,7 @@ Renders images. Allows to define an alternative text and a title attribute for t :: - SELECT "<path to image>|[<alt text>]|[<title text>]" AS _img + 10.sql = SELECT "<path to image>|[<alt text>]|[<title text>]" AS _img .. @@ -6073,10 +5831,11 @@ Runs batch files or executables on the webserver. In case of an error, returncod Column: _pdf | _file | _zip ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Most of the other Link-Class attributes can be used to customize the link. -:: +Detailed explanation: download_ - SELECT "[options]" AS _pdf, "[options]" AS _file, "[options]" AS _zip +Most of the other Link-Class attributes can be used to customize the link. :: + + 10.sql = SELECT "[options]" AS _pdf, "[options]" AS _file, "[options]" AS _zip with: [options] = [d:<exportFilename][|p:<params>][|U:<params>][|u:<url>][|F:file][|t:<text>][|a:<message>][|o:<tooltip>][|c:<class>][|r:<render mode>] @@ -6086,24 +5845,26 @@ Most of the other Link-Class attributes can be used to customize the link. * For column `_pdf` and `_zip`, the element sources `p:...`, `U:...`, `u:...`, `F:...` might repeated multiple times. * Example: :: - SELECT "F:fileadmin/test.pdf" as _pdf, "F:fileadmin/test.pdf" as _file, "F:fileadmin/test.pdf" as _zip - SELECT "p:id=export&r=1" as _pdf, "p:id=export&r=1" as _file, "p:id=export&r=1" as _zip + 10.sql = SELECT "F:fileadmin/test.pdf" as _pdf, "F:fileadmin/test.pdf" as _file, "F:fileadmin/test.pdf" as _zip + 10.sql = SELECT "p:id=export&r=1" as _pdf, "p:id=export&r=1" as _file, "p:id=export&r=1" as _zip - SELECT "t:Download PDF|F:fileadmin/test.pdf" as _pdf, "t:Download PDF|F:fileadmin/test.pdf" as _file, "t:Download ZIP|F:fileadmin/test.pdf" as _zip - SELECT "t:Download PDF|p:id=export&r=1" as _pdf, "t:Download PDF|p:id=export&r=1" as _file, "t:Download ZIP|p:id=export&r=1" as _zip + 10.sql = SELECT "t:Download PDF|F:fileadmin/test.pdf" as _pdf, "t:Download PDF|F:fileadmin/test.pdf" as _file, "t:Download ZIP|F:fileadmin/test.pdf" as _zip + 10.sql = SELECT "t:Download PDF|p:id=export&r=1" as _pdf, "t:Download PDF|p:id=export&r=1" as _file, "t:Download ZIP|p:id=export&r=1" as _zip - SELECT "d:complete.pdf|t:Download PDF|F:fileadmin/test1.pdf|F:fileadmin/test2.pdf" as _pdf, "d:complete.zip|t:Download ZIP|F:fileadmin/test1.pdf|F:fileadmin/test2.pdf" as _zip + 10.sql = SELECT "d:complete.pdf|t:Download PDF|F:fileadmin/test1.pdf|F:fileadmin/test2.pdf" as _pdf, "d:complete.zip|t:Download ZIP|F:fileadmin/test1.pdf|F:fileadmin/test2.pdf" as _zip - SELECT "d:complete.pdf|t:Download PDF|F:fileadmin/test.pdf|p:id=export&r=1|u:www.example.com" AS _pdf + 10.sql = SELECT "d:complete.pdf|t:Download PDF|F:fileadmin/test.pdf|p:id=export&r=1|u:www.example.com" AS _pdf .. _column_ppdf: Column: _Pdf | _File | _Zip ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Detailed explanation: download_ + A limited set of attributes is supported: :: - SELECT "[options]" AS _Pdf, "[options]" AS _File, "[options]" AS _Zip + 10.sql = SELECT "[options]" AS _Pdf, "[options]" AS _File, "[options]" AS _Zip with: [options] = [<exportFilename>]|[<text>]|[<1: urlparam|file>]|[<2: urlparam|file>]| ... |[<n: urlparam|file>] @@ -6217,31 +5978,273 @@ QFQ returns a HTML 'img'-tag: :: <img src="{{thumbnailDirPublic:Y}}/<md5 hash>.png"> -Typical +.. _column-monitor: -QFQ CSS Classes ---------------- +Column: _monitor +^^^^^^^^^^^^^^^^ -* `qfq-table-50`, `qfq-table-80`, `qfq-table-100` - set min-width and column width to 'auto' -* Background Color: `qfq-color-grey-1`, `qfq-color-grey-2` (table, row, cell) -* `qfq-100`: Makes an element 'width: 100%'. -* `qfq-left`: Text align left. +Detailed explanation: monitor_ -Bootstrap -^^^^^^^^^ +**Syntax** :: -* Table: `table` -* Table > hover: `table-hover` -* Table > condensed: `table-condensed` + 10.sql = SELECT 'file:<filename>|tail:<number of last lines>|append:<0 or 1>|interval:<time in ms>|htmlId:<id>' AS _monitor -E.g.:: ++-------------+-------------------------------------------------------------------------------------------+---------------------------+ +|**Parameter**|**Description** |**Default value/behaviour**| ++=============+===========================================================================================+===========================+ +|<filename> |The path to the file. Relative to T3 installation directory or absolute. |none | ++-------------+-------------------------------------------------------------------------------------------+---------------------------+ +|<tail> |Number of last lines to show |30 | ++-------------+-------------------------------------------------------------------------------------------+---------------------------+ +|<append> |0: Retrieved content replaces current. 1: Retrieved content will be added to current. |0 | ++-------------+-------------------------------------------------------------------------------------------+---------------------------+ +|<htmlId> |Reference to HTML element to whose content replaced by the retrieve one. |monitor-1 | ++-------------+-------------------------------------------------------------------------------------------+---------------------------+ - 10.sql = SELECT id, name, firstName, ... - 10.head = <table class='table table-condensed qfq-table-50'> -* `qfq-100`, `qfq-left` - makes e.g. a button full width and aligns the text left. :: +.. _download: - 10.sql = SELECT "p:home&r=0|t:Home|c:qfq-100 qfq-left" AS _pagev +Download +-------- + +Download offers: + +* download a single file (any type), +* concatenate several files (uploaded) and/or web pages (=HTML to PDF) into one PDF output file, +* create a ZIP archive, filled with several files ('uploaded' or 'HTML to PDF'-converted). + +The downloads are SIP protected. Only the current user can use the link to download files. + +By using the `_link` columnname: + +* the option `d:...` initiate creating the download link and optional specifies an export filename, +* the optional `M:...` (Mode) specifies the export type (file, pdf, zip), +* setting `s:1` is mandatory for the download function, +* the alttext `a:...` specifies a message in the download popup. + +By using `_pdf`, `_Pdf`, `_file`, `_File`, `_zip`, `_Zip` as columnname, the options `d`, `m` and `s` +will be set by automatically. + +All files will be read by PHP - therefore the directory might be protected against direct web access. This way is the +preferred way to offer secure downloads via QFQ. + +In case the download needs a persistant URL (no SIP, no user session), a regular +link, pointing directly to a file, have to be used - the download functionality described here is not appropriate for +such a scenario. + +.. _download-parameter-files: + +Parameter and (element) sources +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* *download*: `d[:<exportFilename>]` + + * *exportFilename* = <filename for save as> - Name, offered in the 'File save as' browser dialog. Default: 'output.<ext>'. + + If there is no `exportFilename` defined, then the original filename is taken. + + The user typically expects meaningful and distinct filenames for different download links. + +* *popupMessage*: `a:<text>` - will be displayed in the popup window during download. If the creating/download is fast, the window might disappear quickly. + +* *mode*: `M:<mode>` + + * *mode* = <file | pdf | zip> - This parameter is optional and can be skipped in most situations. Mandatory + for 'zip'. + + * If `M:file`, the mime type is derived dynamically from the specified file. In this mode, only one element source + is allowed per download link (no concatenation). + + * In case of multiple element sources, only `pdf` or `zip` is supported. + * If `M:zip` is used together with `p:...`, `U:...` or `u:..`, those HTML pages will be converted to PDF. Those files + get generic filenames inside the archive. + * If not specified, the **default** 'Mode' depends on the number of specified element sources (=file or web page): + + * If only one `file` is specifed, the default is `file`. + * If there is a) a page defined or b) multiple elements, the default is `pdf`. + +* *element sources* - for `M:pdf` or `M:zip`, all of the following three element sources might be specified multiple times. Any combination and order of the three options are allowed. + + * *file*: `F:<pathFileName>` - relative or absolute pathFileName offered for a) download (single), or to be concatenated + in a PDF or ZIP. + * *page*: `p:id=<t3 page>&<key 1>=<value 1>&<key 2>=<value 2>&...&<key n>=<value n>`. + + * By default, the options given to wkhtml will *not* be encoded by a SIP! + * To encode the parameter via SIP: Add '_sip=1' to the URL GET parameter. + + E.g. `p:id=form&_sip=1&form=Person&r=1`. + + In that way, specific sources for the `download` might be SIP encrypted. + + * Any current HTML cookies will be forwarded to/via `wkhtml`. This includes the current FE Login as well as any + QFQ session. Also the current User-Agent are faked via the `wkhtml` page request. + + * If there are trouble with accessing FE_GROUP protected content, please check `wkhtmltopdf`_. + + * *url*: `u:<url>` - any URL, pointing to an internal or external destination. + + * *WKHTML Options* for `page`, `urlParam` or `url`: + + * The 'HTML to PDF' will be done via `wkhtmltopdf`. + * All possible options, suitable for `wkhtmltopdf`, can be submitted in the `p:...`, `u:...` or `U:...` element source. + Check `wkhtmltopdf.txt <https://wkhtmltopdf.org/usage/wkhtmltopdf.txt>`_ for possible options. Be aware that + key/value tuple in the documentation is separated by a space, but to respect the QFQ key/value notation of URLs, + the key/value tuple in `p:...`, `u:...` or `U:...` has to be separated by '='. Please see last example below. + + Most of the other Link-Class attributes can be used to customize the link as well. + +Example `_link`: :: + + # single `file`. Specifying a popup message window text is not necessary, cause a file directly accessed is fast. + SELECT "d:file.pdf|s|t:Download|F:fileadmin/pdf/test.pdf" AS _link + + # single `file`, with mode + SELECT "d:file.pdf|M:pdf|s|t:Download|F:fileadmin/pdf/test.pdf" AS _link + + # three sources: two pages and one file + SELECT "d:complete.pdf|s|t:Complete PDF|p:id=detail&r=1|p:id=detail2&r=1|F:fileadmin/pdf/test.pdf" AS _link + + # three sources: two pages and one file + SELECT "d:complete.pdf|s|t:Complete PDF|p:id=detail&r=1|p:id=detail2&r=1|F:fileadmin/pdf/test.pdf" AS _link + + # three sources: two pages and one file, parameter to wkhtml will be SIP encoded + SELECT "d:complete.pdf|s|t:Complete PDF|p:id=detail&r=1&_sip=1|p:id=detail2&r=1&_sip=1|F:fileadmin/pdf/test.pdf" AS _link + + # three sources: two pages and one file, the second page will be in landscape and pagesize A3 + SELECT "d:complete.pdf|s|t:Complete PDF|p:id=detail&r=1|p:id=detail2&r=1&--orientation=Landscape&--page-size=A3|F:fileadmin/pdf/test.pdf" AS _link + +.. + +Example `_pdf`, `_zip`: :: + + # File 1: p:id=1&--orientation=Landscape&--page-size=A3 + # File 2: p:id=form + # File 3: F:fileadmin/file.pdf + SELECT 't:PDF|a:Creating a new PDF|p:id=1&--orientation=Landscape&--page-size=A3|p:id=form|F:fileadmin/file.pdf' AS _pdf + + # File 1: p:id=1 + # File 2: u:http://www.example.com + # File 3: F:fileadmin/file.pdf + SELECT 't:PDF - 3 Files|a:Please be patient|p:id=1|u:http://www.example.com|F:fileadmin/file.pdf' AS _pdf + + # File 1: p:id=1 + # File 2: p:id=form + # File 3: F:fileadmin/file.pdf + SELECT CONCAT('t:ZIP - 3 Pages|a:Please be patient|p:id=1|p:id=form|F:', p.pathFileName) AS _zip + +.. + +Use the `--print-media-type` as wkhtml option to access the page with media type 'printer'. Depending on the website +configuration this switches off navigation and background images. + +Rendering PDF letters +^^^^^^^^^^^^^^^^^^^^^ + +`wkhtmltopdf`, with the header and footer options, can be used to render multi page PDF letters (repeating header, +pagination) in combination with dynamic content. Such PDFs might look-alike official letters, together with logo and signature. + +Best practice: + +#. Create a clean (=no menu, no website layout) letter layout in a separated T3 branch: :: + + page = PAGE + page.typeNum = 0 + page.includeCSS { + 10 = typo3conf/ext/qfq/Resources/Public/Css/qfq-letter.css + } + + // Grant access to any logged in user or specific development IPs + [usergroup = *] || [IP = 127.0.0.1,192.168.1.* ] + page.10 < styles.content.get + [else] + page.10 = TEXT + page.10.value = access forbidden + [global] + +#. Create a T3 `body` page (e.g. page alias: 'letterbody') with some content. Example static HTML content: :: + + <div class="letter-receiver"> + <p>Address</p> + </div> + <div class="letter-sender"> + <p><b>firstName name</b><br> + Phone +00 00 000 00 00<br> + Fax +00 00 000 00 00<br> + </p> + </div> + + <div class="letter-date"> + Zurich, 01.12.2017 + </div> + + <div class="letter-body"> + <h1>Subject</h1> + + <p>Dear Mrs...</p> + <p>Lucas ipsum dolor sit amet organa solo skywalker darth c-3p0 anakin jabba mara greedo skywalker.</p> + + <div class="letter-no-break"> + <p>Regards</p> + <p>Company</p> + <img class="letter-signature" src=""> + <p>Firstname Name<br>Function</p> + </div> + </div> + +#. Create a T3 letter-`header` page (e.g. page alias: 'letterheader') , with only the header information: :: + + <header> + <img src="fileadmin/logo.png" class="letter-logo"> + + <div class="letter-unit"> + <p class="letter-title">Department</p> + <p> + Company name<br> + Company department<br> + Street<br> + City + </p> + </div> + </header> + +#. Create a) a link (Report) to the PDF letter or b) attach the PDF (on the fly rendered) to a mail. Both will call the + `wkhtml` via the `download` mode and forwards the necessary parameter. + +Use in `report`: :: + + sql = SELECT CONCAT('d:Letter.pdf|t:',p.firstName, ' ', p.name, + '|p:id=letterbody&pId=', p.id, '&_sip=1&--margin-top=50mm&--margin-bottom=20mm&', + '--header-html={{BASE_URL_PRINT:Y}}?id=letterheader&', + '--footer-right="Seite: [page]/[toPage]"&', + '--footer-font-size=8&--footer-spacing=10') AS _pdf + FROM Person AS p ORDER BY p.id + + +Sendmail. Parameter: :: + + sendMailAttachment={{SELECT 'd:Letter.pdf|t:', p.firstName, ' ', p.name, '|p:id=letterbody&pId=', p.id, '&_sip=1&--margin-top=50mm&--margin-bottom=20mm&--header-html={{BASE_URL_PRINT:Y}}?id=letterheader&--footer-right="Seite: [page]/[toPage]"&--footer-font-size=8&--footer-spacing=10' FROM Person AS p WHERE p.id={{id:S}} }} + +Replace the static content elements from 2. and 3. by QFQ Content elements as needed: :: + + 10.sql = SELECT '<div class="letter-receiver"><p>', p.name AS '_+br', p.street AS '_+br', p.city AS '_+br', '</p>' + FROM Person AS p WHERE p.id={{pId:S}} + + +Export area +^^^^^^^^^^^ + +To offer protected pages, e.g. referenced in download links, the regular FE_GROUPs can't be used, cause the download does +not have the current user privileges (it's a separate process, started as the webserver user). + +Create a separated export tree in Typo3 Backend, which is IP access restricted. Only localhost or the FE_GROUP 'admin' +is allowed to access: :: + + [IP = {$tmp.restrictedIPRange} ][usergroup = admin] + page.10 < styles.content.get + [else] + page.10 = TEXT + page.10.value = Please access from localhost or log in as 'admin' user. + [global] .. _drag_and_drop: @@ -6374,6 +6377,49 @@ QFQ iterates over the result set of `dragAndDropOrderSql`. The value of column ` If you find that the reorder does not work at expected, those two sql queries are not identically. +QFQ CSS Classes +--------------- + +* `qfq-table-50`, `qfq-table-80`, `qfq-table-100` - set min-width and column width to 'auto' +* Background Color: `qfq-color-grey-1`, `qfq-color-grey-2` (table, row, cell) +* `qfq-100`: Makes an element 'width: 100%'. +* `qfq-left`: Text align left. + +Bootstrap +--------- + +* Table: `table` +* Table > hover: `table-hover` +* Table > condensed: `table-condensed` + +E.g.:: + + 10.sql = SELECT id, name, firstName, ... + 10.head = <table class='table table-condensed qfq-table-50'> + +* `qfq-100`, `qfq-left` - makes e.g. a button full width and aligns the text left. :: + + 10.sql = SELECT "p:home&r=0|t:Home|c:qfq-100 qfq-left" AS _pagev + +.. _monitor: + +Monitor +------- + +Display a (log)file from the server, inside the browser, which updates automatically by a user defined interval. Access +to the file is SIP protected. Any file on the server is possible. + +* On a Typo3 page, define a HTML element with a unique html-id. E.g.: :: + + 10.head = <pre id="monitor-1">Please wait</pre> + +* On the same Typo3 page, define a SQL column '_monitor' with the necessary parameter: :: + + 10.sql = SELECT 'file:typo3conf/sql.log|tail:50|append:1|refresh:1000|htmlId:monitor-1' AS _monitor + + # Short version with all defaults used. + 10.sql = SELECT 'file:typo3conf/sql.log' AS _monitor + Report Examples --------------- diff --git a/extension/qfq/api/download.php b/extension/qfq/api/download.php index 05c1873e7..43612b78c 100644 --- a/extension/qfq/api/download.php +++ b/extension/qfq/api/download.php @@ -25,17 +25,19 @@ set_error_handler("\\qfq\\ErrorHandler::exception_error_handler"); $data = ''; try { - $download = new \qfq\Download(); - - // If all is fine - 'process()' never returns! The output file is delivered and PHP is stopped after that. - $data = $download->process(STORE_SIP, OUTPUT_MODE_DIRECT); - -} catch (qfq\CodeException $e) { - $data = $e->formatMessage(); -} catch (qfq\DbException $e) { - $data = $e->formatMessage(); -} catch (qfq\DownloadException $e) { - $data = $e->formatMessage(); + try { + $download = new \qfq\Download(); + + // If all is fine - 'process()' never returns! The output file is delivered and PHP is stopped after that. + $data = $download->process(STORE_SIP, OUTPUT_MODE_DIRECT); + + } catch (qfq\CodeException $e) { + $data = $e->formatMessage(); + } catch (qfq\DbException $e) { + $data = $e->formatMessage(); + } catch (qfq\DownloadException $e) { + $data = $e->formatMessage(); + } } catch (\Exception $e) { $data = "Exception: " . $e->getMessage(); } diff --git a/extension/qfq/qfq/AbstractBuildForm.php b/extension/qfq/qfq/AbstractBuildForm.php index 5f3e6d454..7f6577f3c 100644 --- a/extension/qfq/qfq/AbstractBuildForm.php +++ b/extension/qfq/qfq/AbstractBuildForm.php @@ -2769,7 +2769,7 @@ abstract class AbstractBuildForm { * @param string $mode * * mode=RETURN_URL: return complete URL * * mode=RETURN_SIP: returns only the sip - * * mode=RETURN_ARRAY: returns array with url ('_url') and all decoded and created + * * mode=RETURN_ARRAY: returns array with url ('sipUrl') and all decoded and created * parameters. * * @return string String: "API_DIR/delete.php?sip=...." diff --git a/extension/qfq/qfq/Constants.php b/extension/qfq/qfq/Constants.php index 33a8cf17e..ec0828034 100644 --- a/extension/qfq/qfq/Constants.php +++ b/extension/qfq/qfq/Constants.php @@ -146,11 +146,11 @@ const ERROR_UNKNOWN_MODE = 1032; const ERROR_NOT_IMPLEMENTED = 1033; const ERROR_RESERVED_KEY_NAME = 1034; const ERROR_MISSING_FORM = 1035; -const ERROR_MISSING_PARAMETER_FILE = 1035; const ERROR_UNKNOWN_FORWARD_MODE = 1036; const ERROR_MISSING_MESSAGE_FAIL = 1037; const ERROR_MISSING_EXPECT_RECORDS = 1038; const ERROR_MISSING_HIDDEN_FIELD_IN_SIP = 1039; +const ERROR_MISSING_PARAMETER_FILE = 1040; const ERROR_UNKNOWN_CHECKTYPE = 1042; const ERROR_PATTERN_VIOLATION = 1043; @@ -579,6 +579,7 @@ const SIP_MODE_ANSWER = '_modeAnswer'; // Mode how delete() will answer to clien const SIP_FORM = CLIENT_FORM; const SIP_TABLE = 'table'; // delete a record from 'table' const SIP_URLPARAM = 'urlparam'; +const SIP_SIP_URL = 'sipUrl'; const SIP_MAKE_URLPARAM_UNIQ = '_makeUrlParamUniq'; // SIPs for 'new records' needs to be uniq per TAB! Therefore add a uniq parameter const SIP_DOWNLOAD_PARAMETER = '_b64_download'; // Parametername, filled in SIP, to hold all download element parameter. @@ -1298,6 +1299,11 @@ const DOWNLOAD_SIP_ENCODE_PARAMETER = '_sip'; const OUTPUT_MODE_DIRECT = 'direct'; const OUTPUT_MODE_FILE = 'file'; +const MONITOR_TAIL_DEFAULT = 30; +const MONITOR_APPEND_DEFAULT = 0; +const MONITOR_INTERVAL_DEFAULT = 1000; +const MONITOR_HTML_ID_DEFAULT = 'monitor-1'; + // HTML2PDF const HTML2PDF_PAGEID = 'id'; const HTML2PDF_PARAM_GET = 'paramGet'; @@ -1358,6 +1364,10 @@ const TOKEN_L_APPEND = 'append'; const TOKEN_L_INTERVAL = 'interval'; const TOKEN_L_HTML_ID = 'htmlId'; +const MONITOR_MODE_APPEND_0 = '0'; +const MONITOR_MODE_APPEND_1 = '1'; +const MONITOR_SESSION_FILE_SEEK = 'monitor-seek-file'; + const RENDER_MODE_1 = '1'; const RENDER_MODE_2 = '2'; diff --git a/extension/qfq/qfq/report/Download.php b/extension/qfq/qfq/report/Download.php index cb475e614..1aae741f1 100644 --- a/extension/qfq/qfq/report/Download.php +++ b/extension/qfq/qfq/report/Download.php @@ -21,7 +21,7 @@ require_once(__DIR__ . '/../helper/Sanitize.php'); require_once(__DIR__ . '/../helper/HelperFile.php'); require_once(__DIR__ . '/../report/Html2Pdf.php'); require_once(__DIR__ . '/Thumbnail.php'); -//require_once(__DIR__ . '/Sendmail.php'); +require_once(__DIR__ . '/Monitor.php'); require_once(__DIR__ . '/../exceptions/DownloadException.php'); //require_once(__DIR__ . '/../Evaluate.php'); //require_once(__DIR__ . '/../helper/KeyValueStringParser.php'); @@ -71,6 +71,7 @@ class Download { * @throws CodeException * @throws DbException * @throws UserFormException + * @throws UserReportException */ public function __construct($phpUnit = false) { @@ -300,7 +301,8 @@ class Download { if($downloadMode == DOWNLOAD_MODE_MONITOR){ $monitor = new Monitor(); - return $monitor->tailCustom($vars[TOKEN_L_FILE], $vars[TOKEN_L_TAIL]); + + return $monitor->dump($vars[TOKEN_L_FILE], $vars[TOKEN_L_TAIL], $vars[TOKEN_L_APPEND]); } if ($downloadMode == DOWNLOAD_MODE_THUMBNAIL) { diff --git a/extension/qfq/qfq/report/Link.php b/extension/qfq/qfq/report/Link.php index 4eea72435..a8135f5d3 100644 --- a/extension/qfq/qfq/report/Link.php +++ b/extension/qfq/qfq/report/Link.php @@ -835,8 +835,7 @@ class Link { if ($vars[NAME_SIP] === "1") { $paramArray = $this->sip->queryStringToSip($urlNParam, RETURN_ARRAY); - //TODO: Index '_url' umbnennen - $urlNParam = $paramArray['_url']; + $urlNParam = $paramArray[SIP_SIP_URL]; if (Support::findInSet(SYSTEM_SHOW_DEBUG_INFO_YES, $this->store->getVar(SYSTEM_SHOW_DEBUG_INFO, STORE_SYSTEM))) { $vars[NAME_TOOL_TIP] .= PHP_EOL . PHP_EOL . $this->sip->debugSip($paramArray); diff --git a/extension/qfq/qfq/report/Monitor.php b/extension/qfq/qfq/report/Monitor.php index ccdfa783b..f845934f7 100644 --- a/extension/qfq/qfq/report/Monitor.php +++ b/extension/qfq/qfq/report/Monitor.php @@ -10,10 +10,14 @@ namespace qfq; +use PHPUnit\Exception; + +require_once(__DIR__ . '/../store/Session.php'); require_once(__DIR__ . '/../store/Store.php'); require_once(__DIR__ . '/../helper/Support.php'); require_once(__DIR__ . '/../helper/Token.php'); require_once(__DIR__ . '/../helper/OnString.php'); +require_once(__DIR__ . '/../exceptions/DownloadException.php'); //use qfq; @@ -28,18 +32,26 @@ class Monitor { */ private $store = null; + /** + * @var Session + */ + private $session = null; + /** * @param bool|false $phpUnit * @throws CodeException * @throws UserFormException + * @throws UserReportException */ public function __construct($phpUnit = false) { $this->store = Store::getInstance(); + $this->session = Session::getInstance($phpUnit); } /** * Renders some JS to monitor a file on the server. - * $str: 'file:typo3conf/sql.log|tail:1000|append:1|interval:1000|htmlId:monitor1' + * Report: $str: 'file:typo3conf/sql.log|tail:1000|append:1|interval:1000|htmlId:monitor1' + * Fetch: download.php?s=<sip> with sip: file=<filename>&tail=<number of lines> * * @param string $str * @@ -58,20 +70,29 @@ class Monitor { } // 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'); + Support::setIfNotSet($control, TOKEN_L_TAIL, MONITOR_TAIL_DEFAULT); + $isContinuous = Support::setIfNotSet($control, TOKEN_L_APPEND, MONITOR_APPEND_DEFAULT) == MONITOR_MODE_APPEND_1 ? 'true' : 'false'; + $interval = Support::setIfNotSet($control, TOKEN_L_INTERVAL, MONITOR_INTERVAL_DEFAULT); + $htmlId = Support::setIfNotSet($control, TOKEN_L_HTML_ID, MONITOR_HTML_ID_DEFAULT); // 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); + $queryString = DOWNLOAD_MODE . '=' . DOWNLOAD_MODE_MONITOR . + '&' . TOKEN_L_FILE . '=' . $control[TOKEN_L_FILE] . + '&' . TOKEN_L_TAIL . '=' . $control[TOKEN_L_TAIL] . + '&' . TOKEN_L_APPEND . '=' . $control[TOKEN_L_APPEND]; +// $url = store::getSipInstance()->queryStringToSip(API_DIR . '/' . API_DOWNLOAD_PHP . '?' . $queryString, RETURN_URL); + $arr = store::getSipInstance()->queryStringToSip('../../../qfq/api/' . API_DOWNLOAD_PHP . '?' . $queryString, RETURN_ARRAY); + $url = $arr[SIP_SIP_URL]; + + // On page reload, take care to remove optional exsiting old seek position. + $key = $this->getSeekSessionKey($arr[CLIENT_SIP]); + $this->session::unsetItem($key); $code = <<<EOF <script type="text/javascript"> $(document).ready(function () { var getFile = new QfqNS.DisplayFile({ - webworker: "Worker/GetFileContent.js", + webworker: "typo3conf/ext/qfq/Resources/Public/JavaScript/GetFileContent.js", filePath: "$url", interval: $interval, targetId: "$htmlId", @@ -85,17 +106,92 @@ EOF; return $code; } + /** + * @param $filepath + * @param int $lines + * @param $modeAppend + * @return string + * @throws CodeException + * @throws DownloadException + * @throws UserFormException + */ + public function dump($filepath, $lines, $modeAppend) { + + // Retrieve always the last $lines + if ($modeAppend == MONITOR_MODE_APPEND_0) { + return $this->tailCustom($filepath, $lines); + } + + // First call to this file in this session. + $f = $this->open($filepath); + + // Check if there is already a seek position. + $key = $this->getSeekSessionKey($this->store->getVar(SIP_SIP, STORE_SIP)); + $seek = $this->session::get($key); + if ($seek === false) { + + // Get seek position EOF + fseek($f, 0, SEEK_END); + $seek = ftell($f); + + // Store the position in session. + $this->session::set($key, $seek); + + // On initial call, get the specified last $lines. + return $this->tailCustom($filepath, $lines, true, $f); + } + + fseek($f, $seek, SEEK_SET); + $output = fread($f, 8192); + $this->session::set($key, ftell($f)); + + return $output; + } + + /** + * @param $sip + * @return string + */ + private function getSeekSessionKey($sip){ + return MONITOR_SESSION_FILE_SEEK . '-' . $sip; + } + + /** + * @param string $filepath + * @param string $mode + * @return bool|resource + * @throws DownloadException + */ + private function open($filepath, $mode = 'rb') { + + // Open file + $f = @fopen($filepath, $mode); + if ($f === false) { + throw new DownloadException ("Error open '" . $filepath . "': " . error_get_last(), ERROR_IO_CHDIR); + } + + return $f; + } + + /** * 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/ + * + * @param string $filepath + * @param int $lines + * @param bool $adaptive + * @return string + * @throws DownloadException */ - public function tailCustom($filepath, $lines = 1, $adaptive = true) { + private function tailCustom($filepath, $lines = 1, $adaptive = true, $f = null) { // Open file - $f = @fopen($filepath, "rb"); - if ($f === false) return false; + if ($f === null) { + $f = $this->open($filepath); + } // Sets buffer size, according to the number of lines to retrieve. // This gives a performance boost when reading a few lines from the file. diff --git a/extension/qfq/qfq/report/Report.php b/extension/qfq/qfq/report/Report.php index 606758e50..dfa690e9f 100644 --- a/extension/qfq/qfq/report/Report.php +++ b/extension/qfq/qfq/report/Report.php @@ -36,6 +36,7 @@ require_once(__DIR__ . '/../Evaluate.php'); require_once(__DIR__ . '/../helper/KeyValueStringParser.php'); require_once(__DIR__ . '/../helper/Token.php'); require_once(__DIR__ . '/Thumbnail.php'); +require_once(__DIR__ . '/Monitor.php'); const DEFAULT_QUESTION = 'question'; const DEFAULT_ICON = 'icon'; diff --git a/extension/qfq/qfq/store/Sip.php b/extension/qfq/qfq/store/Sip.php index 949cfc7eb..4422e2c1f 100644 --- a/extension/qfq/qfq/store/Sip.php +++ b/extension/qfq/qfq/store/Sip.php @@ -48,7 +48,7 @@ class Sip { * @return string/array * * mode=RETURN_URL: return complete URL * * mode=RETURN_SIP: returns only the sip - * * mode=RETURN_ARRAY: returns array with url ('_url') and all decoded and created parameters. + * * mode=RETURN_ARRAY: returns array with url ('sipUrl') and all decoded and created parameters. * @throws CodeException * @throws UserFormException */ @@ -91,11 +91,11 @@ class Sip { $script = $phpScriptName . $script; } - $clientArray['_url'] = $script . OnArray::toString($clientArray) . $anchor; + $clientArray[SIP_SIP_URL] = $script . OnArray::toString($clientArray) . $anchor; switch ($mode) { case RETURN_URL: - $rc = $clientArray['_url']; + $rc = $clientArray[SIP_SIP_URL]; break; case RETURN_SIP: $rc = $s; -- GitLab