Commit d5c2d74b authored by Carsten  Rose's avatar Carsten Rose
Browse files

Merge branch 'develop' into 'master'

Develop

See merge request !293
parents 453cce90 a78ec8dc
Pipeline #4211 passed with stages
in 4 minutes and 59 seconds
......@@ -12,6 +12,7 @@
.webprj
.vscode
nbprojec
nohup.out
# Created by .ignore support plugin (hsz.mobi)
.python_virtualenv/
......@@ -29,13 +30,11 @@ nbprojec
.support_plantuml
.support_sonar
qfq.flowchart.dia.autosave
test.json
test.php
test.html
*.autosave
composer.lock
/test.*
/Documentation-GENERATED-temp
/bower_components
/composer.phar
......@@ -57,6 +56,7 @@ composer.lock
/extension/Resources/Public/webfonts
/extension/Resources/Public/JavaScript
/extension/Tests/selenium/tmp
/extension/Resources/Private/OnlineRecruitingTool
/fonts
/webfonts
/js
......@@ -72,4 +72,7 @@ composer.lock
/docker/chromedriver
/docker/geckodriver
/docker/run_qfq_docker.output
__pycache__
package-lock.json
......@@ -249,3 +249,14 @@ To allow it, add 'span' to the valid elements in the FormElement.parameter field
The HTML span tag has to be added via 'source' view. At least in TinyMCE 4.7.13, the glyph is still not shown in the
editor.
FE User
-------
The FE User record (table: fe_users)
* Has to exist.
* Has to be assigned to at least one FE Group. Check ``fe_users.usergroup``.
* Has to be assigned to a T3 page ``fe_users.pid``.
* The T3 page has to be configured as ``record store`` on the T3 Plugin login box.
* Access time has to be zero or a currently valid period.
\ No newline at end of file
......@@ -52,7 +52,7 @@ To decide which Parameter should be placed on *Form.parameter* and which on *For
+-----------------------------+----------------------------------+---------------------------------------------------------------------+------+-------------+----------+
| Parameter | Example | Description | Form | FormElement | Used for |
+=============================+==================================+=====================================================================+======+=============+==========+
| ldapServer | directory.example.com | Hostname. For LDAPS: `ldaps://directory.example.com:636` | x | x | TA, FSL |
| ldapServer | ldaps://directory.example.com:636| Hostname. | x | x | TA, FSL |
+-----------------------------+----------------------------------+---------------------------------------------------------------------+------+-------------+----------+
| ldapBaseDn | ou=Addressbook,dc=example,dc=com | Base DN to start the search | x | x | TA, FSL |
+-----------------------------+----------------------------------+---------------------------------------------------------------------+------+-------------+----------+
......@@ -105,7 +105,7 @@ The *FormElement.parameter*=*typeAheadLdap* will trigger LDAP searches on every
* *FormElement.parameter.typeAheadLdap* - activate the mode *Typeahead* - no value is needed, the existence is sufficient.
* *Form.parameter* or *FormElement.parameter*:
* *ldapServer* = `directory.example.com`
* *ldapServer* = `ldaps://directory.example.com:636`
* *ldapBaseDn* = `ou=Addressbook,dc=example,dc=com`
* *typeAheadLdapSearch* = `(|(cn=*?*)(mail=*?*))`
* *typeAheadLdapValuePrintf* = `'%s / %s', cn, email`
......@@ -213,7 +213,7 @@ Action Elements.
* *FormElement.parameter.fillStoreLdap* - activate the mode *Fill S* - no value is needed, the existence is sufficient.
* *Form.parameter* or *FormElement.parameter*:
* *ldapServer* = `directory.example.com`
* *ldapServer* = `ldaps://directory.example.com:636`
* *ldapBaseDn* = `ou=Addressbook,dc=example,dc=com`
* *typeAheadLdapSearch* = `(|(cn=*?*)(mail=*?*))`
* *ldapAttributes* = `givenName, sn, telephoneNumber, email`
......
......@@ -70,6 +70,8 @@ All data will imported / exported in JSON notation.
Any QFQ form becomes a REST form via: ``Form > Access > Permit REST: get / insert / update / delete``
If the REST endpoint specifies an unknown form or access is forbidden, an HTTP error is reported.
Endpoint
--------
......@@ -86,8 +88,8 @@ E.g.:
1. List of all persons: ``<domain>/typo3conf/ext/qfq/Classes/Api/rest.php/person``
2. Data of person 123: ``<domain>/typo3conf/ext/qfq/Classes/Api/rest.php/person/123``
3. Adresses of person 123: ``<domain>/typo3conf/ext/qfq/Classes/Api/rest.php/person/123/address``
4. Adress details of address 45 from person 123: ``<domain>/typo3conf/ext/qfq/Classes/Api/rest.php/person/123/address/45``
3. Addresses of person 123: ``<domain>/typo3conf/ext/qfq/Classes/Api/rest.php/person/123/address``
4. Address details of address 45 from person 123: ``<domain>/typo3conf/ext/qfq/Classes/Api/rest.php/person/123/address/45``
QFQ 'Forms' are used as a 'container' (to define all details).
......@@ -115,11 +117,11 @@ GET - Read
A REST (GET) form has two modes:
data
Specific content to a given id. Defined via 'form.parameter.restSqlData'. This mode is selected if there is an
Specific content to a given id. Defined via ``form.parameter.restSqlData``. This mode is selected if there is an
id>0 given.
list
A list of records will be exported. Defined via 'form.parameter.restSqlList'. This mode is selected if there is no
A list of records will be exported. Defined via ``form.parameter.restSqlList``. This mode is selected if there is no
id or id=0.
.. note::
......@@ -199,12 +201,14 @@ POST - Insert
+-------------------+----------------------------------------------------------------------------------+
| restToken | Optional. User defined string or dynamic token (see :ref:`restAuthorization`). |
+-------------------+----------------------------------------------------------------------------------+
| restSqlPostPut | Optional. Instead of returning the last_insert_id, a customized result might be |
| | specified. E.g. ``{{! SELECT id, token FROM Token WHERE id={{id:R0}} }}`` |
+-------------------+----------------------------------------------------------------------------------+
FormElement:
* For each column to save one FormElement with ``FE.name=<column>`` is necessary.
* A regular QFQ form can be used as REST Post endpoint
* A regular QFQ form can be used as REST Post endpoint.
PUT - Update
------------
......
......@@ -54,7 +54,6 @@ Features
* #10979 / Report: do SIP protected AJAX calls to typo3conf/ext/qfq/Classes/Api/dataReport.php.
* #11076 / Report: trigger call to websockets.
* #11118 / Retrieve random string which is guaranteed to be uniq: {{randomUniq:V}}.
* #11119 / Report: REST Client calls - incl. processing of answer.
* Add CodingGuideline.rst.
......
......@@ -250,6 +250,7 @@ QFQ also provides access to the following stores via the template context.
* typo3
* user
* system
* var
All stores are accessed using their lower case name as attribute of the
context variable `store`. The active Typo3 front-end user is therefore available as::
......@@ -655,6 +656,8 @@ Summary:
+------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| _exec | :ref:`column_exec` - Run batch files or executables on the webserver. |
+------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| _script | :ref:`column_script` - Run php function defined in an external script |
+------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| _vertical | :ref:`column_vertical` - Render Text vertically. This is useful for tables with limited column width. |
+------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| _img | :ref:`column_img` - Display images. |
......@@ -1059,8 +1062,8 @@ Column: _Paged
::
"[table=<table name>&r-<record id>[&param=value&...] | [text] | [tooltip] | [question parameter] | [class] | [render mode]" as _Paged.
"[form=<form name>&r-<record id>[&param=value&...] | [text] | [tooltip] | [question parameter] | [class] | [render mode]" as _Paged.
"[table=<table name>&r=<record id>[&param=value&...] | [text] | [tooltip] | [question parameter] | [class] | [render mode]" as _Paged.
"[form=<form name>&r=<record id>[&param=value&...] | [text] | [tooltip] | [question parameter] | [class] | [render mode]" as _Paged.
.. _column_vertical:
......@@ -1399,6 +1402,98 @@ Run any command on the web server.
10.sql = SELECT "ls -s" AS _exec
20.sql = SELECT "./batchfile.sh" AS _exec
.. _column_script:
Column: _script
^^^^^^^^^^^^^^^
Run a php function defined in an external script.
* All **column parameters are passed** as an associative array to the function as the first argument.
* The second argument (here called $qfq) is an object which acts as an **interface to QFQ functionality** (see below).
* The **current working directory** inside the function is the current web instance (e.g. location of index.php).
* Hint: Inside the script ``dirname(__FILE__)`` gives the path of the script.
* All **output (e.g. using echo) will be rendered** by the special column as is.
* If the function returns an associative array, then the **key-value pairs will be accessible via the VARS store `V`**.
* If the function throws an **exception** then a standard QFQ error message is shown.
* Text sent to 'stderr' by the php function is not returned at all.
* The script has access to the following **qfq functions** using the interface (see examples below):
* $qfq::apiCall($method, $url, $data = '', $header = [], $timeout = 5)
* arguments:
* string $method: can be PUT/POST/GET/DELETE
* string $url
* string $data: a json string which will be added as GET parameters or as POST fields respectively.
* array $header: is of the form ['Content-type: text/plain', 'Content-length: 100']
* int $timeout: is the number of seconds to wait until call is aborted.
* return array:
* [0]: Http status code
* [1]: API answer as string.
* $qfq::getVar($key, $useStores = 'FSRVD', $sanitizeClass = '', &$foundInStore = '', $typeMessageViolate = 'c')
* arguments:
* string $key: is the name of qfq variable
* string $useStores: are the stores in which variable is searched (in order from left to right). see :ref:`store`.
* string $sanitizeClass: (see :ref:`sanitize-class`)
* string $foundInStore: is filled with the name of the store in which the variable was found.
* string $typeMessageViolate: defines what to return if the sanitize class was violated:
* 'c' : returns '!!<sanitize class>!!'
* '0' : returns '0'
* 'e' : returns ''
* return string|false:
* The value of the variable if found.
* A placeholder if the variable violates the sanitize class. (see argument `$typeMessageViolate`)
* `false` if the variable was not found.
**Column Parameters**
+-------------------+----------------------------------------------------+------------------------------------------------------------------------------------+
| Token | Example | Comment |
+===================+====================================================+====================================================================================+
| F | F:fileadmin/scripts/my_script.php | Path to the custom script relative to the current web instance |
+-------------------+----------------------------------------------------+------------------------------------------------------------------------------------+
| call | call:my_function | PHP function to call |
+-------------------+----------------------------------------------------+------------------------------------------------------------------------------------+
| arg | arg:a1=Hello&a2=World" | Arguments are parsed and passed to the function together with the other parameters |
+-------------------+----------------------------------------------------+------------------------------------------------------------------------------------+
**Example**
* QFQ report ::
5.sql = SELECT "IAmInRecordStore" AS _savedInRecordStore
10.sql = SELECT "F:fileadmin/scripts/my_script.php|call:my_function|arg:a1=Hello&a2=World" AS _script
20.sql = SELECT "<br><br>Returened value: {{IAmInVarStore:V:alnumx}}"
* PHP script (`fileadmin/scripts/my_script.php`) ::
<?php
function my_function($param, $qfq) {
echo 'The first argument contains all attributes including "F" and "c":<br>';
print_r($param);
echo '<br><br>get variable from record store:<br>';
print_r($qfq::getVar('savedInRecordStore', 'RE'));
echo '<br><br>Make API call:<br>';
list($http_code, $answer) = $qfq::apiCall('GET', 'google.com');
echo 'Http code: ' . $http_code;
// Returned array fills VARS store
return ["IAmInVarStore" => "FooBar"];
}
* Output ::
The first argument contains all parameters including "F", "call" and "arg":
Array ( [a1] => Hello [a2] => World [F] => fileadmin/scripts/my_script.php [call] => my_function [arg] => a1=Hello&a2=World )
get variable from record store:
IAmInRecordStore
Make API call:
Http code: 301
Returened value: FooBar
.. _column_pdf:
......@@ -1599,7 +1694,7 @@ Example::
, 'y:hello world (link)|t:content direct (link)' AS _link
, CONCAT('F:', p.pathFileName,'|t:File (yank)|o:', p.pathFileName) AS _yank
, CONCAT('y|F:', p.pathFileName,'|t:File (link)|o:', p.pathFileName) AS _link
FROM Person AS p  
FROM Person AS p
.. _api_call_qfq_report:
......@@ -1609,30 +1704,35 @@ API Call QFQ Report (e.g. AJAX)
.. note::
QFQ Report functionality protected by SIP offered to simple API calls: ``typo3conf/ext/qfq/Api/dataReport.php?s=....``
QFQ Report functionality protected by SIP offered to simple API calls: ``typo3conf/ext/qfq/Classes/Api/dataReport.php?s=....``
General use API call to fire a specific QFQ tt-content record. Useful for e.g. AJAX calls. No Typo3 is involved.
*No FE-Group access control*.
* General use API call to fire a specific QFQ tt-content record. Useful for e.g. AJAX calls. No Typo3 is involved. *No FE-Group access control*.
* This defines just a simple API endpoint. For defining a rest API see: :ref:`restApi`.
* Custom response headers can be defined by setting the variable `apiResponseHeader` in the record store.
* Multiple headers should be separated by `\n` or `\r\n`. e.g.: `Content-Type: application/json\ncustom-header: fooBar`
* If the api call succeeds the rendered content of the report is returned as is. (no additional formatting, no JSON encoding)
* You can use MYSQL to create Json. See: `MYSQL create Json <https://dev.mysql.com/doc/refman/8.0/en/json-creation-functions.html>`_ and `MariaDB Json functions <https://mariadb.com/kb/en/json-functions/>`_
* If a QFQ error occurs then a http-status of 400 is returned together with a JSON encoded response of the form: `{"status":"error", "message":"..."}`
This describes the client side (=QFQ is client). For server function check :ref:`restApi`.
Example QFQ record JS (with tt_content.uid=12345)::
Example QFQ record JS::
5.sql = SELECT "See console log for output"
# Register SIP with given arguments.
10.sql = SELECT 'U:uid=12345&arg1=Hello&arg2=World|s|r:8' AS '_link|col1'
# Build JS
10.tail = <script>
function writeYourOwnAjax(){
$.ajax({
url: 'typo3conf/ext/qfq/Api/dataReport.php?s={{col1:RE}}',
data: {arg3:456, arg4:567},
method: 'POST',
dataType: 'JSON',
success: function(response) {ajaxSuccess(response);},
error: function(jqXHR, textStatus, errorThrown) {ajaxError(jqXHR, textStatus, errorThrown);}
});
}
</script>
# Register SIP with given arguments.
10.sql = SELECT 'U:uid=12345&arg1=Hello&arg2=World|s|r:8' AS '_link|col1|_hide'
# Build JS
10.tail = <script>
console.log('start api request');
$.ajax({
url: 'typo3conf/ext/qfq/Classes/Api/dataReport.php?s={{&col1:RE}}',
data: {arg3:456, arg4:567},
method: 'POST',
dataType: 'TEXT',
success: function(response, status, jqxhr) {console.log(response); console.log(jqxhr.getAllResponseHeaders());},
error: function(jqXHR, textStatus, errorThrown) {console.log(jqXHR.responseText, textStatus, errorThrown);}
});
</script>
Example QFQ record called by above AJAX::
......@@ -1640,7 +1740,11 @@ Example QFQ record called by above AJAX::
# The example above assumes that this record has the tt_content.uid=12345.
render = api
10.sql = SELECT '{{arg1:S}} {{arg2:S}} {{arg3:C}} {{arg4:C}}', NOW()
, 'Content-Type: application/json\ncustom-header: fooBar' AS _apiResponseHeader
Example text returned by the above AJAX call::
Hello World 456 5672020-09-22 18:09:47
.. _rest_client:
......@@ -1656,7 +1760,7 @@ be processed in subsequent calls.
Example::
# Retrieve information. Received data is delivered in JSON and decoded / copied on the fly to STORE_CLIENT
# Retrieve information. Received data is delivered in JSON and decoded / copied on the fly to CLIENT store (CLIENT store is emptied beforehand)
10.sql = SELECT 'n:https://www.dummy.ord/rest/person/id/123' AS _restClient
20.sql = SELECT 'Status: {{http-status:C}}<br>Name: {{name:C:alnumx}}<br>Surname: {{surname:C:alnumx}}'
......@@ -1668,7 +1772,7 @@ Example::
+===================+================================+============================================================================+
| n | n:https://www.dummy.ord/rest/person | |
+-------------------+----------------------------------------------------+--------------------------------------------------------+
| method | method:POST | GET or POST |
| method | method:POST | GET, POST, PUT or DELETE |
+-------------------+----------------------------------------------------+--------------------------------------------------------+
| content | content:{"name":"John";"surname":"Doe"} | Depending on the REST server JSON might be expected |
+-------------------+----------------------------------------------------+--------------------------------------------------------+
......@@ -1676,12 +1780,10 @@ Example::
+-------------------+----------------------------------------------------+--------------------------------------------------------+
| timeout | timeout:5 | Default: 5 seconds. |
+-------------------+----------------------------------------------------+--------------------------------------------------------+
| ssl | ssl:{"verify_peer":true,"allow_self_signed":false} | JSON config for SSL settings |
+-------------------+----------------------------------------------------+--------------------------------------------------------+
**Header**
* Each header must be separated by ``\r\n``.
* Each header must be separated by ``\r\n`` or `\n`.
* An explicit given header will overwrite the named default header.
* Default header:
......@@ -1696,12 +1798,13 @@ Example::
* The variable ``{{http-status:C}}`` shows the `HTTP status code<https://en.wikipedia.org/wiki/List_of_HTTP_status_codes>`_.
A value starting with '2..' shows success.
* In case of an error, ``{{error-message:C:allbut}}`` shows some details.
* In case the returned answer is a valid JSON string, it's automatically copied STORE_CLIENT with corresponding key names.
* In case the returned answer is a valid JSON string, it is flattened and automatically copied to STORE_CLIENT with corresponding key names.
* NOTE: The CLIENT store is emptied beforehand!
JSON answer example::
Answer from Server: { 'name' : 'John'; 'street': 'Milky road' }
Retrieve the values via: {{name:C:alnumx}}, {{street:C:alnumx}}
Answer from Server: { 'name' : 'John', 'address' : {'city' : 'Bern'} }
Retrieve the values via: {{name:C:alnumx}}, {{city:C:alnumx}}
.. _special-sql-functions:
......@@ -1718,7 +1821,7 @@ In general this function should be used when there is a chance that unplanned '|
Example::
10.sql = SELECT CONCAT('p:notes|t:Information: ', QBAR(Note.title), '|b') AS _link FROM Note  
10.sql = SELECT CONCAT('p:notes|t:Information: ', QBAR(Note.title), '|b') AS _link FROM Note
In case 'Note.title' contains a '|' (like 'fruit | numbers'), it will confuse the '... AS _link' class. Therefore it's
necessary to 'escape' (adding a '\' in front of the problematic character) the bar which is done by using `QBAR()`.
......@@ -1740,7 +1843,7 @@ on a HTML page with correctly displayed linefeed.
Example::
10.sql = SELECT QNL2BR(Note.title) FROM Note  
10.sql = SELECT QNL2BR(Note.title) FROM Note
One possibility how `LF` comes into the database is with form elements of type `textarea` if the user presses `enter` inside.
......
......@@ -256,9 +256,7 @@ Store: *VARS* - V
| Name | Explanation |
+=========================+============================================================================================================================================+
| random | Random string with length of 32 alphanum chars (lower & upper case). This variable is always filled. Each access gives a new value. |
+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+
| randomUniq | Like {{random:V}} but it's guaranteed that it's uniq. Optional: as *default* define an expiration time. Example: ``{{randomUniq:V}}``, |
| | ``{{randomUniq:V:::2020-12-15}}``, ``{{randomUniq:V:::+ 10 sec}}`` (sec, min, day, ... - MySQL notation DATE_ADD() ). |
| | Remember: QFQ variables will be replaced **before** a SQL statement is fired. Uniqueness is given via PHP function *uniqid()*. |
+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+
| slaveId | see :ref:`slave-id` |
+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------+
......
......@@ -127,7 +127,7 @@ For QFQ variables and FormElements:
+------------------+------+-------+-----------------------------------------------------------------------------------------+
| Name | Form | Query | Pattern |
+==================+======+=======+=========================================================================================+
| **alnumx** | Form | Query | [A-Za-z][0-9]@-_.,;: /() ÀÈÌÒÙàèìòùÁÉÍÓÚÝáéíóúýÂÊÎÔÛâêîôûÃÑÕãñõÄËÏÖÜŸäëïöüÿç |
| **alnumx** | Form | Query | [A-Za-z][0-9]@-_.,;: /() ÀÈÌÒÙàèìòùÁÉÍÓÚÝáéíóúýÂÊÎÔÛâêîôûÃÑÕãñõÄËÏÖÜŸäëïöüÿçß |
+------------------+------+-------+-----------------------------------------------------------------------------------------+
| **digit** | Form | Query | [0-9] |
+------------------+------+-------+-----------------------------------------------------------------------------------------+
......@@ -375,4 +375,4 @@ For better reading, the format string might be wrapped in single or double quote
These variables are especially helpful in:
* `report`, to create create links or buttons outside of an SQL statement. E.g. in `head`, `rbeg`, ...
* `form`, to create links and buttons in labels or notes.
\ No newline at end of file
* `form`, to create links and buttons in labels or notes.
......@@ -11,6 +11,7 @@ namespace IMATHUZH\Qfq\Api;
require_once(__DIR__ . '/../../vendor/autoload.php');
use IMATHUZH\Qfq\Core\QuickFormQuery;
use IMATHUZH\Qfq\Core\Store\Store;
/**
......@@ -39,7 +40,19 @@ try {
$qfq = new QuickFormQuery(['bodytext' => '']);
$data = $qfq->dataReport();
// Get custom headers from record store
$headers = Store::getInstance()->getVar(API_HEADER_VARIABLE_KEY, 'RE');
if (!empty($headers)) {
$headers = str_replace("\r\n", '$$SEP$$', $headers);
$headers = str_replace("\n", '$$SEP$$', $headers);
$headers = explode('$$SEP$$', $headers);
} else {
$headers = [];
}
$status = HTTP_200_OK;
} catch (\UserReportException $e) {
$answer[API_MESSAGE] = $e->formatMessage();
} catch (\CodeException $e) {
......@@ -51,7 +64,16 @@ try {
$answer[API_MESSAGE] = "Generic Exception: " . $e->getMessage();
}
//header('HTTP/1.0 ' . $status);
//header("Content-Type: application/json");
//echo json_encode($answer);
// error output
if ($status === HTTP_400_BAD_REQUEST) {
header('HTTP/1.0 ' . $status);
header("Content-Type: application/json");
echo json_encode($answer);
exit();
}
// normal output
foreach ($headers as $header) {
header($header);
}
echo $data;
\ No newline at end of file
......@@ -102,7 +102,7 @@ const SANITIZE_TYPE_MESSAGE_VIOLATE_EMPTY = 'e';
const SANITIZE_TYPE_MESSAGE_VIOLATE_ZERO = '0';
const SANITIZE_TYPE_MESSAGE_VIOLATE_CLASS = 'c';
const PATTERN_ALNUMX = '^[@\-_\.,;: \/\(\)a-zA-Z0-9ÀÈÌÒÙàèìòùÁÉÍÓÚÝáéíóúýÂÊÎÔÛâêîôûÃÑÕãñõÄËÏÖÜŸäëïöüÿç]*$';
const PATTERN_ALNUMX = '^[@\-_\.,;: \/\(\)a-zA-Z0-9ÀÈÌÒÙàèìòùÁÉÍÓÚÝáéíóúýÂÊÎÔÛâêîôûÃÑÕãñõÄËÏÖÜŸäëïöüÿçß]*$';
const PATTERN_DIGIT = '^[\d]*$';
const PATTERN_NUMERICAL = '^[\d.+-]*$';
const PATTERN_EMAIL = '^([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})?$';
......@@ -724,7 +724,6 @@ const SIP_EXCLUDE_XDEBUG_SESSION_START = 'XDEBUG_SESSION_START';
const ACTION_KEYWORD_SLAVE_ID = 'slaveId';
const VAR_RANDOM = 'random';
const VAR_RANDOM_UNIQ = 'randomUniq';
const VAR_FILE_DESTINATION = 'fileDestination';
const VAR_SLAVE_ID = ACTION_KEYWORD_SLAVE_ID;
const VAR_FILENAME = 'filename'; // Original filename of an uploaded file.
......@@ -820,6 +819,7 @@ const API_FORM_UPDATE_VALUE = 'value';
const API_FORM_UPDATE_HIDDEN = 'hidden';
const API_FORM_UPDATE_DISABLED = 'disabled';
const API_FORM_UPDATE_REQUIRED = 'required';
const API_HEADER_VARIABLE_KEY = 'apiResponseHeader';
const API_ELEMENT_UPDATE = 'element-update';
const API_ELEMENT_ATTRIBUTE = 'attr';
......@@ -1069,6 +1069,7 @@ const F_MULTI_MSG_NO_RECORD_TEXT = 'No data';
const F_REST_SQL_LIST = 'restSqlList';
const F_REST_SQL_DATA = 'restSqlData';
const F_REST_SQL_POST_PUT = 'restSqlPostPut';
const F_REST_PARAM = 'restParam';
const F_REST_TOKEN = 'restToken';
const CLIENT_REST_ID = '_id';
......@@ -1606,6 +1607,7 @@ const COLUMN_SENDMAIL = "sendmail";
const COLUMN_VERTICAL = "vertical";
const COLUMN_WEBSOCKET = "websocket";
const COLUMN_REST_CLIENT = "restClient";
const COLUMN_SCRIPT = "script";
const COLUMN_NO_WRAP = "noWrap";
const COLUMN_HIDE = "hide";
......@@ -1763,6 +1765,7 @@ const TOKEN_COPY_TO_CLIPBOARD = 'y';
const TOKEN_DROPDOWN = 'z';
const TOKEN_WEBSOCKET = 'w';
const TOKEN_REST_CLIENT = 'n';
const TOKEN_SCRIPT = 'F';
const TOKEN_TEXT = 't';
const TOKEN_ALT_TEXT = 'a';
......@@ -1790,6 +1793,8 @@ const TOKEN_FILE = 'F';
const TOKEN_FILE_DEPRECATED = 'f'; // since 5.12.17
const TOKEN_DOWNLOAD_MODE = 'M';
const TOKEN_ATTRIBUTE = 'A';
const TOKEN_FUNCTION_CALL = 'call';
const TOKEN_ARGUMENT = 'arg';
const TOKEN_THUMBNAIL = 'T';
const TOKEN_THUMBNAIL_DIMENSION = 'W';
......@@ -2018,4 +2023,4 @@ const I_CHECKED = 'checked';
const I_UNCHECKED = 'unchecked';
const HTTP_STATUS = 'http-status';
const ERROR_MESSAGE = 'error-message';
\ No newline at end of file
const ERROR_MESSAGE = 'error-message';
......@@ -86,7 +86,7 @@ class Database {
// DB Init
if ($dbInit !== false && $dbInit != '') {
$arr = explode(';', $dbInit);
foreach ($arr AS $sql) {
foreach ($arr as $sql) {
$sql = trim($sql);
if ('' != $sql) {
$this->sql($sql);
......@@ -253,6 +253,9 @@ class Database {
default:
throw new \DbException($specificMessage . "Unknown mode: $mode", ERROR_UNKNOWN_MODE);
}
$this->freeResult();
} elseif ($queryType === QUERY_TYPE_INSERT) {
$result = $stat[DB_INSERT_ID];
} else {
......@@ -416,6 +419,7 @@ class Database {
case 'SHOW':
case 'DESCRIBE':
case 'EXPLAIN':
case 'CALL':
if (false === ($result = $this->mysqli_stmt->get_result())) {
throw new \DbException(
json_encode([ERROR_MESSAGE_TO_USER => 'Error DB execute', ERROR_MESSAGE_TO_DEVELOPER => '[ mysqli: ' . $this->mysqli_stmt->errno . ' ] ' . $this->mysqli_stmt->error . $specificMessage]),
......@@ -449,7 +453,6 @@ class Database {
case 'ALTER':
case 'DROP':
case 'CREATE':
case 'CALL':
$queryType = QUERY_TYPE_CONTROL;
$stat[DB_AFFECTED_ROWS] = 0;
$count = $stat[DB_AFFECTED_ROWS];
......@@ -621,7 +624,7 @@ class Database {
}
/**
* Fetch all rows of the result as associative array.
* Fetch all rows of the result.
*
* mode:
* ROW_IMPLODE_ALL: Return string. All cells of all rows imploded to one string.
......@@ -638,6 +641,9 @@ class Database {
*
*/
private function fetchAll($mode = '', &$keys = array()) {
$result = null;
if ($this->mysqli_result == null || $this->mysqli_result == false) {
return false;
}
......@@ -648,12 +654,10 @@ class Database {
switch ($mode) {
case ROW_IMPLODE_ALL:
$str = "";
$result = "";
foreach ($this->mysqli_result->fetch_all(MYSQLI_NUM) as $row) {
$str .= implode($row);
$result .= implode($row);
}
return $str;
break;
case ROW_KEYS:
......@@ -663,12 +667,14 @@ class Database {
$keys[$ii] = $this->mysqli_result->fetch_field_direct($ii)->name;
}
return $this->mysqli_result->fetch_all(MYSQLI_NUM);
$result = $this->mysqli_result->fetch_all(MYSQLI_NUM);
break;
default:
return $this->mysqli_result->fetch_all(MYSQLI_ASSOC);
$result = $this->mysqli_result->fetch_all(MYSQLI_ASSOC);
}
return $result;
}
/**
......@@ -740,7 +746,7 @@ class Database {
private function getFieldDefinitionFromTable($table, $columnName) {