Commit 0d1069f6 authored by Carsten  Rose's avatar Carsten Rose
Browse files

Refs #12636. Form: a) Single Tick encode for {{10.line.content::s}}, b) new...

Refs #12636. Form: a) Single Tick encode for {{10.line.content::s}}, b) new encoding type 'single tick'. Part a implemented. Test missing.
parent 045802ef
Pipeline #5275 passed with stages
in 3 minutes and 48 seconds
......@@ -249,7 +249,7 @@ class Evaluate {
* @throws \UserFormException
* @throws \UserReportException
*/
private function inlineLink($arrToken, $dbIndex, &$foundInStore) {
private function inlineLink($arrToken, $dbIndex, &$foundInStore): string {
$token = OnString::trimQuote(trim(implode(' ', $arrToken)));
......@@ -262,31 +262,6 @@ class Evaluate {
return $this->link->renderLink($token);
}
/**
* Get the CET/CEST Timezone for a given date, or if date is '' based on the current date.
*
* @param string $dateStr
* @return string // CET, CEST or GMT+?/GMT-?
*/
public function getEuropeanTimezone($dateStr = '') {
$ts = ($dateStr == '') ? time() : strtotime($dateStr);
$offset = date("Z", $ts) / 3600;
switch ($offset) {
case 1:
$tz = "CET";
break;
case 2:
$tz = "CEST";
break;
default:
$tz = 'GMT' . sprintf("%+d", $offset);
}
return $tz;
}
/**
* @param $arrToken
* @param $dbIndex
......@@ -296,7 +271,7 @@ class Evaluate {
* @throws \UserFormException
* @throws \UserReportException
*/
private function inlineDataDndApi($arrToken, $dbIndex, &$foundInStore) {
private function inlineDataDndApi($arrToken, $dbIndex, &$foundInStore): string {
$token = OnString::trimQuote(trim(implode(' ', $arrToken)));
......@@ -344,7 +319,7 @@ class Evaluate {
$token = trim($token);
$dbIndex = $this->dbIndex;
$flagWipe = false;
$rcFlagWipe = false;
// Check if the $token starts with '[<int>]...' - yes: open the necessary database.
if (strlen($token) > 2 && $token[0] === '[') {
......@@ -421,64 +396,7 @@ class Evaluate {
$value = $this->store::getVar($arrToken[VAR_INDEX_VALUE], $arrToken[VAR_INDEX_STORE], $arrToken[VAR_INDEX_SANITIZE],
$foundInStore, $typeMessageViolate, $arrToken[VAR_INDEX_DEFAULT]);
// escape ticks
if (is_string($value)) {
// Process all escape requests in the given order.
for ($ii = 0; $ii < strlen($escapeTypes); $ii++) {
$escape = $escapeTypes[$ii];
if ($escape == TOKEN_ESCAPE_CONFIG) {
$escape = $this->escapeTypeDefault;
}
switch ($escape) {
case TOKEN_ESCAPE_SINGLE_TICK:
$value = str_replace("'", "\\'", $value);
break;
case TOKEN_ESCAPE_DOUBLE_TICK:
$value = str_replace('"', '\\"', $value);
break;
case TOKEN_ESCAPE_COLON:
$value = str_replace(':', '\\:', $value);
break;
case TOKEN_ESCAPE_LDAP_FILTER:
$value = Support::ldap_escape($value, null, LDAP_ESCAPE_FILTER);
break;
case TOKEN_ESCAPE_LDAP_DN:
$value = Support::ldap_escape($value, null, LDAP_ESCAPE_DN);
break;
case TOKEN_ESCAPE_MYSQL:
$value = $this->dbArray[$dbIndex]->realEscapeString($value);
break;
case TOKEN_ESCAPE_NONE: // do nothing
break;
case TOKEN_ESCAPE_PASSWORD_T3FE:
$value = T3Handler::getHash($value);
break;
case TOKEN_ESCAPE_STOP_REPLACE:
$value = Support::encryptDoubleCurlyBraces($value);
break;
case TOKEN_ESCAPE_EXCEPTION:
// empty values will be handled later.
break;
case TOKEN_ESCAPE_WIPE:
$flagWipe = true;
break;
case TOKEN_ESCAPE_TIMEZONE:
$value = $this->getEuropeanTimezone($value);
break;
case TOKEN_ESCAPE_HTML_SPECIAL_CHAR:
$value = Support::htmlEntityEncodeDecode(MODE_ENCODE, $value);
break;
default:
throw new \UserFormException("Unknown escape qualifier: $escape", ERROR_UNKNOW_SANITIZE_CLASS);
break;
}
}
} else {
// In case the value is not found and the escape class forces a full stop
if (strpos($escapeTypes, TOKEN_ESCAPE_EXCEPTION) !== false) {
throw new \UserFormException($arrToken[VAR_INDEX_MESSAGE] ?? '', ERROR_QUIT_QFQ_REGULAR);
}
}
$value = OnString::escape($escapeTypes, $value, $rcFlagWipe);
// Not found and a default is given: take the default.
if ($foundInStore == '' && $arrToken[VAR_INDEX_DEFAULT] != '') {
......@@ -486,7 +404,7 @@ class Evaluate {
$value = str_replace('\\:', ':', $arrToken[VAR_INDEX_DEFAULT]);
}
if ($flagWipe) {
if ($rcFlagWipe) {
switch ($foundInStore) {
case STORE_SIP:
$this->store::unsetVar($arrToken[VAR_INDEX_VALUE], STORE_SIP);
......
......@@ -9,12 +9,26 @@
namespace IMATHUZH\Qfq\Core\Helper;
use IMATHUZH\Qfq\Core\Database\Database;
use IMATHUZH\Qfq\Core\Store\Store;
use IMATHUZH\Qfq\Core\Typo3\T3Handler;
/**
* Class OnString
* @package qfq
*/
class OnString {
/**
* @var Store
*/
private static $store = null;
/**
* @var Database
*/
private static $db = null;
/**
* Returns part of haystack string starting from and including the last occurrence of needle to the end of haystack.
*
......@@ -372,5 +386,126 @@ class OnString {
$rcFunctionParam = OnArray::trimArray(explode(',', $args[0] ?? ''));
$rcReturnParam = OnArray::trimArray(explode(',', $split[1] ?? ''));
}
/**
* Escape $value by list of $escapeTypes.
*
* @param $escapeTypes
* @param $value
* @param $rcFlagWipe
* @return string
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
* @throws \UserReportException
*/
public static function escape($escapeTypes, $value, &$rcFlagWipe) {
// escape ticks
if (is_string($value)) {
// Process all escape requests in the given order.
for ($ii = 0; $ii < strlen($escapeTypes); $ii++) {
$escape = $escapeTypes[$ii];
if ($escape == TOKEN_ESCAPE_CONFIG) {
$escape = self::getEscapeTypeDefault();
}
switch ($escape) {
case TOKEN_ESCAPE_SINGLE_TICK:
$value = str_replace("'", "\\'", $value);
break;
case TOKEN_ESCAPE_DOUBLE_TICK:
$value = str_replace('"', '\\"', $value);
break;
case TOKEN_ESCAPE_COLON:
$value = str_replace(':', '\\:', $value);
break;
case TOKEN_ESCAPE_LDAP_FILTER:
$value = Support::ldap_escape($value, null, LDAP_ESCAPE_FILTER);
break;
case TOKEN_ESCAPE_LDAP_DN:
$value = Support::ldap_escape($value, null, LDAP_ESCAPE_DN);
break;
case TOKEN_ESCAPE_MYSQL:
if (self::$db === null) {
self::$db = new Database();
}
$value = self::$db->realEscapeString($value);
break;
case TOKEN_ESCAPE_NONE: // do nothing
break;
case TOKEN_ESCAPE_PASSWORD_T3FE:
$value = T3Handler::getHash($value);
break;
case TOKEN_ESCAPE_STOP_REPLACE:
$value = Support::encryptDoubleCurlyBraces($value);
break;
case TOKEN_ESCAPE_EXCEPTION:
// empty values will be handled in 'else'.
break;
case TOKEN_ESCAPE_WIPE:
$rcFlagWipe = true;
break;
case TOKEN_ESCAPE_TIMEZONE:
$value = self::getEuropeanTimezone($value);
break;
case TOKEN_ESCAPE_HTML_SPECIAL_CHAR:
$value = Support::htmlEntityEncodeDecode(MODE_ENCODE, $value);
break;
default:
throw new \UserFormException("Unknown escape qualifier: $escape", ERROR_UNKNOW_SANITIZE_CLASS);
break;
}
}
} else {
// In case the value is not found and the escape class forces a full stop
if (strpos($escapeTypes, TOKEN_ESCAPE_EXCEPTION) !== false) {
throw new \UserFormException($arrToken[VAR_INDEX_MESSAGE] ?? '', ERROR_QUIT_QFQ_REGULAR);
}
}
return $value;
}
/**
* @return string
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
* @throws \UserReportException
*/
private static function getEscapeTypeDefault() {
static $escapeTypeDefault = null;
if ($escapeTypeDefault === null) {
self::$store = Store::getInstance();
$escapeTypeDefault = self::$store->getVar(F_ESCAPE_TYPE_DEFAULT, STORE_SYSTEM);
}
return $escapeTypeDefault;
}
/**
* Get the CET/CEST Timezone for a given date, or if date is '' based on the current date.
*
* @param string $dateStr
* @return string
*/
public static function getEuropeanTimezone($dateStr = '') {
$ts = ($dateStr == '') ? time() : strtotime($dateStr);
$offset = date("Z", $ts) / 3600;
switch ($offset) {
case 1:
$tz = "CET";
break;
case 2:
$tz = "CEST";
break;
default:
$tz = 'GMT' . sprintf("%+d", $offset);
}
return $tz;
}
}
......@@ -24,6 +24,7 @@
namespace IMATHUZH\Qfq\Core\Report;
use IMATHUZH\Qfq\Core\Evaluate;
use IMATHUZH\Qfq\Core\Helper\OnString;
use IMATHUZH\Qfq\Core\Store\T3Info;
......@@ -37,6 +38,7 @@ class Variables {
// TODO to explain
private $tt_content_uid = 0;
/**
* @var Evaluate
*/
......@@ -74,47 +76,46 @@ class Variables {
// $str = preg_replace_callback("/{{(([a-zA-Z0-9.:_])*)}}/", array($this, 'replaceVariables'), $text);
// Process all {{x[.x].name}}
$str = preg_replace_callback('/{{\s*(([0-9]+.)+[a-zA-Z0-9_.]+)\s*}}/', array($this, 'replaceVariables'), $text);
// $str = preg_replace_callback('/{{\s*(([0-9]+.)+[a-zA-Z0-9_.]+)\s*}}/', 'self::replaceVariables', $text);
$str = preg_replace_callback('/{{\s*(([0-9]+.)+[a-zA-Z0-9_.]+)(:.*)*\s*}}/', 'self::replaceVariables', $text);
// Try the Stores
$str = $this->eval->parse($str);
return $str;
return $this->eval->parse($str);
}
/**
* Callbackfunction called by variableSQL()
* Replaces the variablenames with the value from the resultArray
* Replaces the variablenames with the value from the resultArray.
* a) 10.<colname>
* b) 10.line.total|count|insertId|content
*
* @param $matches
*
* @return string The content that is displayed on the website
* @internal param string $content : The PlugIn content
* @internal param array $conf : The PlugIn configuration
*/
public function replaceVariables($matches) {
public function replaceVariables($matches): string {
// $matches[0]: {{variablename: 10.20.<columnname>}}
// $matches[1]: variablename: 10.20.<columnname>
// $matches[0]: {{10.20.<columnname>::u:}}
// $matches[1]: 10.20.<columnname>
// $matches[2]: 10.20
// $matches[3]: ::u:
$data = $matches[0];
// index of last '.'
$pos = strrpos($matches[1], ".");
if ($pos !== false) {
$fullLevel = substr($matches[1], 0, $pos + 1);
$varName = substr($matches[1], $pos + 1, strlen($matches[1]));
if (isset($this->resultArray[$fullLevel][$varName])) {
//
$data = $this->resultArray[$fullLevel][$varName];
if (isset($matches[3])) {
$data = OnString::escape($matches[3], $this->resultArray[$fullLevel][$varName], $rcFlagWipe);
}
}
}
// If not replaced, try the Stores
// if ($data === $matches[0]) {
// $dataTmp = $this->eval->parse($data);
// if ($dataTmp !== false)
// $data = $dataTmp;
// }
return $data;
}
......@@ -126,7 +127,7 @@ class Variables {
*
* @return array with global variables which might be replaced
*/
public function collectGlobalVariables() {
public function collectGlobalVariables(): array {
$arr = array();
if (isset($_SERVER["REMOTE_ADDR"])) {
......@@ -156,12 +157,12 @@ class Variables {
$arr["be_user_uid"] = (isset($GLOBALS['BE_USER'])) ? $GLOBALS['BE_USER']->user["uid"] : '-';
$arr["ttcontent_uid"] = $this->tt_content_uid;
if (isset($GLOBALS["TSFE"])) {
$arr["page_id"] = $GLOBALS["TSFE"]->id;
$arr["page_type"] = $GLOBALS["TSFE"]->type;
$arr["page_language_uid"] = T3Info::getLanguageId();
}
return ($arr);
......
......@@ -6,8 +6,6 @@
namespace IMATHUZH\Qfq\Tests\Unit\Core;
use IMATHUZH\Qfq\Core\BuildFormPlain;
use IMATHUZH\Qfq\Core\Helper\Path;
use IMATHUZH\Qfq\Core\Helper\Support;
use IMATHUZH\Qfq\Core\QuickFormQuery;
use IMATHUZH\Qfq\Tests\Unit\Core\Database\AbstractDatabaseTest;
......@@ -395,6 +393,7 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
$form = array();
$formElement = array();
$json = array();
$baseUrl = $this->store->getVar(SYSTEM_BASE_URL, STORE_SYSTEM);
$this->templateFormNFormElement($form, $formElement);
$formElement = Support::setFeDefaults($formElement);
......@@ -478,7 +477,7 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
// _id: 1, icon: bullet-green.gif
$formElement['sql1'] = $this->dbArray[DB_INDEX_DEFAULT]->sql('SELECT id AS "_id", "bullet-green.gif" AS "Status|icon" FROM Person ORDER BY id LIMIT 2');
$result = $build->buildSubrecord($formElement, 'name:1', '', $json);
$this->assertEquals('<table class="' . SUBRECORD_TABLE_CLASS_DEFAULT . '" id="1-123" ><thead><tr><th>Status</th></tr></thead><tbody ><tr class="record" ><td><image src=\'http://xxxxxxxxxxxxxxxxxxxxxxxxxxxx/qfq/typo3conf/ext/qfq/Resources/Public/icons/bullet-green.gif\'></td></tr><tr class="record" ><td><image src=\'http://xxxxxxxxxxxxxxxxxxxxxxxxxxxx/qfq/typo3conf/ext/qfq/Resources/Public/icons/bullet-green.gif\'></td></tr></tbody></table>', $result);
$this->assertEquals('<table class="' . SUBRECORD_TABLE_CLASS_DEFAULT . '" id="1-123" ><thead><tr><th>Status</th></tr></thead><tbody ><tr class="record" ><td><image src=\'' . $baseUrl . 'typo3conf/ext/qfq/Resources/Public/icons/bullet-green.gif\'></td></tr><tr class="record" ><td><image src=\'' . $baseUrl . 'typo3conf/ext/qfq/Resources/Public/icons/bullet-green.gif\'></td></tr></tbody></table>', $result);
// _id: 1, mailto: john@doe.com
$formElement['sql1'] = $this->dbArray[DB_INDEX_DEFAULT]->sql('SELECT id AS "_id", "john@doe.com" AS "EMail|mailto" FROM Person ORDER BY id LIMIT 2');
......
......@@ -600,42 +600,6 @@ class EvaluateTest extends AbstractDatabaseTest {
$eval->parse('go {{unknownVar:S::X}} stop');
}
/**
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
* @throws \UserReportException
*/
public function testGetEuropeanTimezone() {
$eval = new Evaluate($this->store, $this->dbArray[DB_INDEX_DEFAULT]);
// It seems in phpunit there is no default time zone set - set it manually.
date_default_timezone_set('Europe/Berlin');
# Check 2020 incl. hour
$this->assertEquals('CET', $eval->getEuropeanTimezone('29.03.2020 01:00'));
$this->assertEquals('CEST', $eval->getEuropeanTimezone('29.03.2020 03:00'));
$this->assertEquals('CEST', $eval->getEuropeanTimezone('25.10.2020 01:00'));
$this->assertEquals('CET', $eval->getEuropeanTimezone('25.10.2020 03:00'));
# Check 2021 incl. hour
$this->assertEquals('CET', $eval->getEuropeanTimezone('28.03.2021 01:00'));
$this->assertEquals('CEST', $eval->getEuropeanTimezone('28.03.2021 03:00'));
$this->assertEquals('CEST', $eval->getEuropeanTimezone('31.10.2021 01:00'));
$this->assertEquals('CET', $eval->getEuropeanTimezone('31.10.2021 03:00'));
# Check 2021 only date
$this->assertEquals('CET', $eval->getEuropeanTimezone('28.03.2021'));
$this->assertEquals('CEST', $eval->getEuropeanTimezone('29.03.2021'));
$this->assertContains($eval->getEuropeanTimezone(''), ['CET', 'CEST']);
# Check if action parameter 't' is recognized.
$this->store->setVar('start', '02.06.2020', STORE_FORM, true);
$this->assertEquals('CEST', $eval->substitute('start:F:all:t', $foundInStore));
}
/**
*/
protected function setUp() {
......
......@@ -8,7 +8,6 @@
namespace IMATHUZH\Qfq\Tests\Unit\Core\Helper;
use IMATHUZH\Qfq\Core\Helper\OnString;
use PHPUnit\Framework\TestCase;
......@@ -200,4 +199,39 @@ class OnStringTest extends TestCase {
public function testRemoveNewlinesInNestedExpression_missingOpening_3() {
$str = OnString::removeNewlinesInNestedExpression("{{Test}}}}");
}
/**
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
* @throws \UserReportException
*/
public function testGetEuropeanTimezone() {
// It seems in phpunit there is no default time zone set - set it manually.
date_default_timezone_set('Europe/Berlin');
# Check 2020 incl. hour
$this->assertEquals('CET', OnString::getEuropeanTimezone('29.03.2020 01:00'));
$this->assertEquals('CEST', OnString::getEuropeanTimezone('29.03.2020 03:00'));
$this->assertEquals('CEST', OnString::getEuropeanTimezone('25.10.2020 01:00'));
$this->assertEquals('CET', OnString::getEuropeanTimezone('25.10.2020 03:00'));
# Check 2021 incl. hour
$this->assertEquals('CET', OnString::getEuropeanTimezone('28.03.2021 01:00'));
$this->assertEquals('CEST', OnString::getEuropeanTimezone('28.03.2021 03:00'));
$this->assertEquals('CEST', OnString::getEuropeanTimezone('31.10.2021 01:00'));
$this->assertEquals('CET', OnString::getEuropeanTimezone('31.10.2021 03:00'));
# Check 2021 only date
$this->assertEquals('CET', OnString::getEuropeanTimezone('28.03.2021'));
$this->assertEquals('CEST', OnString::getEuropeanTimezone('29.03.2021'));
$this->assertContains(OnString::getEuropeanTimezone(''), ['CET', 'CEST']);
# Check if action parameter 't' is recognized.
// $this->store->setVar('start', '02.06.2020', STORE_FORM, true);
// $this->assertEquals('CEST', $eval->substitute('start:F:all:t', $foundInStore));
}
}
\ No newline at end of file
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