Commit b6c43d4a authored by Marc Egger's avatar Marc Egger

add special column AS _script

parent 2a61e45e
Pipeline #3817 passed with stages
in 4 minutes and 34 seconds
......@@ -655,6 +655,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. |
......@@ -1399,6 +1401,87 @@ 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.
* The script has access to the following qfq functions using this interface:
* $qfq::apiCall($method, $url, $data = [], $header = [], $timeout = 5)
* string $method can be PUT/POST/GET/DELETE
* string $url
* array $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.
* $qfq::getVar($key, $useStores = 'FSRVD', $sanitizeClass = '', &$foundInStore = '', $typeMessageViolate = 'c')
* 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': return '!!<sanitize class>!!'
* '0': return '0'
* 'e': return ''
* The current working directory is the current web instance (e.g. ``/var/www/html``) .
* All output (e.g. using echo) will be returned by the special column as is.
* If the function returns an associative array, then the key-value pairs will be accessible via the Client store.
* Text sent to 'stderr' by the php function is not returned at all.
**Column Parameters**
+-------------------+----------------------------------------------------+------------------------------------------------------------------+
| Token | Example | Comment |
+===================+====================================================+==================================================================+
| scr | scr:fileadmin/scripts/my_script.php | Path to the custom script relative to the current web instance |
+-------------------+----------------------------------------------------+------------------------------------------------------------------+
| f | f:my_function | Function name |
+-------------------+----------------------------------------------------+------------------------------------------------------------------+
| <whatever> | myParameter:something | All parameters are passed on in an associative array |
+-------------------+----------------------------------------------------+------------------------------------------------------------------+
**Example**
* PHP script (fileadmin/scripts/my_script.php) ::
<?php
function my_function($param, $qfq) {
echo 'The first argument contains all attributes including "src" and "f":<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 client store
return ["IAmInClientStore" => "FooBar"];
}
* QFQ report ::
5.sql = SELECT "IAmInRecordStore" AS _savedInRecordStore
10.sql = SELECT "scr:fileadmin/scripts/my_script.php|f:my_function|a1:Hello|a2:World" AS _script
20.sql = SELECT "<br><br>Returened value: {{IAmInClientStore:C:alnumx}}"
* Output ::
The first argument contains all attributes including "src" and "f":
Array ( [scr] => fileadmin/scripts/my_script.php [f] => my_function [a1] => Hello [a2] => World )
get variable from record store:
IAmInRecordStore
Make API call:
Http code: 301
Returened value: FooBar
.. _column_pdf:
......
......@@ -1605,6 +1605,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";
......@@ -1762,6 +1763,7 @@ const TOKEN_COPY_TO_CLIPBOARD = 'y';
const TOKEN_DROPDOWN = 'z';
const TOKEN_WEBSOCKET = 'w';
const TOKEN_REST_CLIENT = 'n';
const TOKEN_SCRIPT = 'scr';
const TOKEN_TEXT = 't';
const TOKEN_ALT_TEXT = 'a';
......@@ -1789,6 +1791,7 @@ 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 = 'f';
const TOKEN_THUMBNAIL = 'T';
const TOKEN_THUMBNAIL_DIMENSION = 'W';
......@@ -2017,4 +2020,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';
<?php
namespace IMATHUZH\Qfq\Core\Report;
use IMATHUZH\Qfq\Core\Helper\KeyValueStringParser;
use IMATHUZH\Qfq\Core\Store\Store;
/**
* Class ColumnScript
* @package IMATHUZH\Qfq\Core\Report
*
* Executes a function of an external script. Column parameters:
* scr: path to script
* f: function name
*
* All parameters are passed to the function as the first argument.
* The second argument passed is an instance of ScriptFunctions which acts as an interface to QFQ functionality.
*/
class ColumnScript {
public function render(string $columnValue) {
// Parse arguments
$param = KeyValueStringParser::parse($columnValue, PARAM_TOKEN_DELIMITER, PARAM_DELIMITER);
if (empty($param[TOKEN_SCRIPT])) {
throw new \UserReportException("Missing script path.", ERROR_MISSING_VALUE);
}
if (empty($param[TOKEN_FUNCTION])) {
throw new \UserReportException("Missing function name.", ERROR_MISSING_VALUE);
}
// include script
$scriptPath = getcwd() . '/' . $param[TOKEN_SCRIPT];
if (!is_readable($scriptPath)) {
throw new \UserReportException("Can't read script file.", ERROR_IO_READ_FILE);
}
try {
if((include_once $scriptPath) === false)
{
throw new \Exception('Include failed.');
}
} catch (\Exception | \Error $e) {
throw new \UserReportException(json_encode([
ERROR_MESSAGE_TO_USER => 'Error during reading script file.',
ERROR_MESSAGE_TO_DEVELOPER => "Error meassage:\n" . $e->getMessage()]));
}
// execute function, write output to buffer
if (!function_exists($param[TOKEN_FUNCTION])) {
throw new \UserReportException("Function doesn't exist.", ERROR_IO_READ_FILE);
}
ob_start();
try {
$return = call_user_func_array($param[TOKEN_FUNCTION], [$param, new ScriptFunctions()]);
$output = ob_get_clean();
} catch (\Exception | \Error $e) {
ob_end_clean();
throw new \UserReportException(json_encode([
ERROR_MESSAGE_TO_USER => 'Function execution failed.',
ERROR_MESSAGE_TO_DEVELOPER => "Error message:\n" . $e->getMessage() . "\n\nFunction: " . $param[TOKEN_FUNCTION] . "\n\nParameters:\n" . print_r($param,true)]));
}
// return buffer output and fill store
Store::setStore($return, STORE_CLIENT, true);
return $output;
}
}
/**
* Class ScriptFunctions
* @package IMATHUZH\Qfq\Core\Report
*
* An instance of this class is passed as the last argument to every external function call.
* WARNING: Be aware that this acts as a "public" interface to QFQ. All changes made in here might break existing applications.
*/
class ScriptFunctions {
public static function apiCall(string $method, string $url, string $data = '', array $header = [], int $timeout = 5) {
return RestClient::callApiCurl($method, $url, $data, $header, $timeout);
}
public static function getVar($key, $useStores = STORE_USE_DEFAULT, $sanitizeClass = '', &$foundInStore = '',
$typeMessageViolate = SANITIZE_TYPE_MESSAGE_VIOLATE_CLASS) {
return Store::getInstance()->getVar($key, $useStores, $sanitizeClass, $foundInStore,
$typeMessageViolate);
}
}
......@@ -942,6 +942,9 @@ class Report {
case COLUMN_REST_CLIENT:
$content .= $this->link->renderLink($columnValue);
break;
case COLUMN_SCRIPT:
$content .= ColumnScript::render($columnValue);
break;
case COLUMN_EXEC:
$rc = '';
......
......@@ -126,7 +126,7 @@ class RestClient {
return $param;
}
private static function callApiCurl(string $method, string $url, string $data = '', array $header = [], int $timeout = 5) {
public static function callApiCurl(string $method, string $url, string $data = '', array $header = [], int $timeout = 5) {
$ch = curl_init();
$curlConfig = array(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment