Commit 77e35128 authored by Carsten  Rose's avatar Carsten Rose
Browse files

Fixes #12636. Implements FormElement.encoding = 'single tick'

parent 0d386f88
Pipeline #5285 passed with stages
in 3 minutes and 31 seconds
......@@ -21,6 +21,7 @@ use IMATHUZH\Qfq\Core\Helper\OnArray;
use IMATHUZH\Qfq\Core\Helper\Path;
use IMATHUZH\Qfq\Core\Helper\Sanitize;
use IMATHUZH\Qfq\Core\Helper\Support;
use IMATHUZH\Qfq\Core\Helper\OnString;
use IMATHUZH\Qfq\Core\Report\Link;
use IMATHUZH\Qfq\Core\Report\Report;
use IMATHUZH\Qfq\Core\Store\Sip;
......@@ -862,6 +863,8 @@ abstract class AbstractBuildForm {
if ($formElement[FE_ENCODE] === FE_ENCODE_SPECIALCHAR) {
// $value = htmlspecialchars_decode($value, ENT_QUOTES);
$value = Support::htmlEntityEncodeDecode(MODE_DECODE, $value);
} elseif ($formElement[FE_ENCODE] === FE_ENCODE_SINGLE_TICK) {
$value = OnString::escapeSingleTickInHtml($value);
}
// Typically: $htmlElementNameIdZero = true
......
......@@ -1332,6 +1332,7 @@ const TYPEAHEAD_PLACEHOLDER = '?';
// Values
const FE_ENCODE_SPECIALCHAR = 'specialchar';
const FE_ENCODE_SINGLE_TICK = 'single tick';
const FE_ENCODE_NONE = 'none';
const FE_FILE_CAPTURE_CAMERA = 'camera';
......
......@@ -204,6 +204,11 @@ $UPDATE_ARRAY = array(
"ALTER TABLE `FormSubmitLog` ADD `formName` VARCHAR(255) NOT NULL DEFAULT '' AFTER `formId`;",
],
'21.6.0' => [
"ALTER TABLE `FormElement` CHANGE `encode` `encode` ENUM('none','specialchar','single tick') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'specialchar';",
],
);
......
......@@ -514,14 +514,13 @@ class OnString {
* @param $line
* @return string
*/
public static function escapeSingleTickInHtml($line) {
public static function escapeSingleTickInHtml($line): string {
$flagTag = false;
$flagAttribute = false;
$flagAttributeStartSingleTick = false;
$flagAttributeStartDoubleTick = false;
$flagAttributeInsideDoubleTick = false;
$flagAttributeStarted = false;
$flagDoubleTickInAttribute = false;
$flagAttibuteNoQuote = false;
$posStartSingleTick = null;
$new = '';
......@@ -536,8 +535,8 @@ class OnString {
$flagDoubleTickInAttribute = false;
$flagAttributeStartSingleTick = false;
$flagAttributeStartDoubleTick = false;
$flagAttributeInsideDoubleTick = false;
$flagAttibuteNoQuote = false;
$flagAttributeStarted = false;
$flagDoubleTickInAttribute = false;
$posStartSingleTick = null;
break;
......@@ -554,47 +553,74 @@ class OnString {
break;
case ' ':
if ($flagTag && ($flagAttributeStartSingleTick || $flagAttributeInsideDoubleTick)) {
// Space after start attribute and no quotes used, means: attribute ends here.
if ($flagTag && $flagAttribute && $flagAttributeStarted && !$flagAttributeStartSingleTick && !$flagAttributeStartDoubleTick) {
$flagAttribute = false;
$flagDoubleTickInAttribute = false;
$flagAttributeStartSingleTick = false;
$flagAttributeStartDoubleTick = false;
$flagAttributeInsideDoubleTick = false;
$flagAttibuteNoQuote = false;
$flagAttributeStarted = false;
$flagDoubleTickInAttribute = false;
$posStartSingleTick = null;
}
break;
case "'":
if ($flagTag) {
if ($flagAttribute && !$flagAttributeStartSingleTick && !$flagAttributeInsideDoubleTick) {
if ($flagAttribute) {
if (!$flagAttributeStartSingleTick && !$flagAttributeStartDoubleTick && !$flagAttributeStarted) {
// Attribute quoted by single tick.
// Remember position to later replace by double tick, if there is no double tick inside.
$flagAttributeStartSingleTick = true;
$posStartSingleTick = strlen($new);
$flagAttributeStarted = true;
break;
}
if ($flagAttribute && $flagAttributeStartSingleTick && !$flagDoubleTickInAttribute) {
if ($flagAttributeStartSingleTick) {
// Closing single tick. Attribute ends here.
$flagAttributeStartSingleTick = false;
$flagAttribute = false;
$flagAttributeStarted = false;
if (!$flagDoubleTickInAttribute) {
// No double tick found: single ticks can be replaced by double tick
$new[$posStartSingleTick] = '"';
$new .= '"';
$flagAttributeStartSingleTick = false;
continue 2;
}
if ($flagAttribute && !$flagAttributeStartSingleTick) {
$flagDoubleTickInAttribute = false;
break;
}
if ($flagAttributeStartDoubleTick) {
// Single tick inside a double tick quoted attribute: can be replaced
$new .= ''';
continue 2;
}
}
} else {
// regular content (no tag)
$new .= ''';
continue 2;
}
break;
case '"':
if ($flagTag) {
if ($flagAttribute) {
if (!$flagAttributeStartSingleTick && !$flagAttributeInsideDoubleTick) {
if (!$flagAttributeStartSingleTick && !$flagAttributeStartDoubleTick && !$flagAttributeStarted) {
// Attribute starting with double tick.
$flagAttributeStartDoubleTick = true;
$flagAttributeStarted = true;
break;
}
if ($flagAttributeStartDoubleTick) {
// Attribute ending with double tick
$flagAttributeStartDoubleTick = false;
$flagAttribute = false;
$flagAttributeStarted = false;
break;
}
if ($flagAttributeStartSingleTick) {
......@@ -602,13 +628,11 @@ class OnString {
break;
}
}
}
break;
default:
if ($flagAttribute) {
if (!$flagAttributeStartSingleTick && !$flagAttributeInsideDoubleTick) {
$flagAttibuteNoQuote = true;
break;
}
$flagAttributeStarted = true;
}
}
$new .= $c;
......
......@@ -962,7 +962,7 @@ class Support {
case FE_TYPE_EDITOR:
case FE_TYPE_TEXT:
if ($formElement[FE_ENCODE] === FE_ENCODE_SPECIALCHAR)
if ($formElement[FE_ENCODE] === FE_ENCODE_SPECIALCHAR || $formElement[FE_ENCODE] === FE_ENCODE_SINGLE_TICK)
$checkType = SANITIZE_ALLOW_ALL;
break;
}
......
......@@ -15,6 +15,7 @@ use IMATHUZH\Qfq\Core\Helper\KeyValueStringParser;
use IMATHUZH\Qfq\Core\Helper\Logger;
use IMATHUZH\Qfq\Core\Helper\Sanitize;
use IMATHUZH\Qfq\Core\Helper\Support;
use IMATHUZH\Qfq\Core\Helper\OnString;
/**
* Class FillStoreForm
......@@ -367,7 +368,10 @@ class FillStoreForm {
if ($formElement[FE_ENCODE] === FE_ENCODE_SPECIALCHAR) {
// $value = htmlspecialchars($value, ENT_QUOTES);
$value = Support::htmlEntityEncodeDecode(MODE_ENCODE, $value);
} elseif ($formElement[FE_ENCODE] === FE_ENCODE_SINGLE_TICK) {
$value = OnString::escapeSingleTickInHtml($value);
}
}
break;
}
......
......@@ -77,7 +77,7 @@ CREATE TABLE IF NOT EXISTS `FormElement`
'beforeSave', 'beforeInsert', 'beforeUpdate', 'beforeDelete', 'afterLoad', 'afterSave',
'afterInsert', 'afterUpdate', 'afterDelete', 'sendMail', 'paste') NOT NULL DEFAULT 'text',
`subrecordOption` SET ('edit', 'delete', 'new') NOT NULL DEFAULT '',
`encode` ENUM ('none', 'specialchar') NOT NULL DEFAULT 'specialchar',
`encode` ENUM ('none', 'specialchar', 'single tick') NOT NULL DEFAULT 'specialchar',
`checkType` ENUM ('auto', 'alnumx', 'digit', 'numerical', 'email', 'pattern', 'allbut',
'all') NOT NULL DEFAULT 'auto',
`checkPattern` VARCHAR(255) NOT NULL DEFAULT '',
......
......@@ -243,17 +243,22 @@ class OnStringTest extends TestCase {
$this->assertEquals("<b>hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b>hel'lo</b>"));
$this->assertEquals('<b>hel"lo</b>', OnString::escapeSingleTickInHtml('<b>hel"lo</b>'));
$this->assertEquals('<b>hel&apos;l"o</b>', OnString::escapeSingleTickInHtml('<b>hel\'l"o</b>'));
$this->assertEquals("<b title=test>hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b title=test>hel'lo</b>"));
$this->assertEquals("<b title = test > hel&apos;lo </b>", OnString::escapeSingleTickInHtml("<b title = test > hel'lo </b>"));
$this->assertEquals("<b title=\"test\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b title='test'>hel'lo</b>"));
$this->assertEquals("<b title = \"test\" > hel&apos;lo </b>", OnString::escapeSingleTickInHtml("<b title = 'test' > hel'lo </b>"));
$this->assertEquals("<b title=\"test\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b title=\"test\">hel'lo</b>"));
$this->assertEquals("<b title= \"test\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b title= 'test'>hel'lo</b>"));
$this->assertEquals("<b title= \"test\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b title= \"test\">hel'lo</b>"));
$this->assertEquals("<b title=\"test\" >hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b title=\"test\" >hel'lo</b>"));
$this->assertEquals("<b title= \"test\" >hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b title= \"test\" >hel'lo</b>"));
$this->assertEquals("<b title=\"te'st\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b title=\"te'st\">hel'lo</b>"));
$this->assertEquals("<b title= \"te'st\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b title= \"te'st\">hel'lo</b>"));
$this->assertEquals("<b title= \"te'st\" >hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b title= \"te'st\" >hel'lo</b>"));
$this->assertEquals("<b title=\"te&apos;st\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b title=\"te'st\">hel'lo</b>"));
$this->assertEquals("<b title= \"te&apos;st\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b title= \"te'st\">hel'lo</b>"));
$this->assertEquals("<b title= \"te&apos;st\" >hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b title= \"te'st\" >hel'lo</b>"));
$this->assertEquals("<b title='te\"st'>hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b title='te\"st'>hel'lo</b>"));
$this->assertEquals("<b title= 'te\"st'>hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b title= 'te\"st'>hel'lo</b>"));
......@@ -268,10 +273,10 @@ class OnStringTest extends TestCase {
$this->assertEquals("<b src=\"gif\" title='te\"st' alt=\"jpg\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b src='gif' title='te\"st' alt=\"jpg\">hel'lo</b>"));
$this->assertEquals("<b src=\"gif\" title='te\"st' alt=\"jpg\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b src=\"gif\" title='te\"st' alt='jpg'>hel'lo</b>"));
$this->assertEquals("<b src=gif title=\"te'st\" alt=jpg>hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b src=gif title=\"te'st\" alt=jpg>hel'lo</b>"));
$this->assertEquals("<b src=\"gif\" title=\"te'st\" alt=\"jpg\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b src='gif' title=\"te'st\" alt='jpg'>hel'lo</b>"));
$this->assertEquals("<b src=\"gif\" title=\"te'st\" alt=\"jpg\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b src=\"gif\" title=\"te'st\" alt='jpg'>hel'lo</b>"));
$this->assertEquals("<b src=\"gif\" title=\"te'st\" alt=\"jpg\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b src='gif' title=\"te'st\" alt=\"jpg\">hel'lo</b>"));
$this->assertEquals("<b src=gif title=\"te&apos;st\" alt=jpg>hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b src=gif title=\"te'st\" alt=jpg>hel'lo</b>"));
$this->assertEquals("<b src=\"gif\" title=\"te&apos;st\" alt=\"jpg\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b src='gif' title=\"te'st\" alt='jpg'>hel'lo</b>"));
$this->assertEquals("<b src=\"gif\" title=\"te&apos;st\" alt=\"jpg\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b src=\"gif\" title=\"te'st\" alt='jpg'>hel'lo</b>"));
$this->assertEquals("<b src=\"gif\" title=\"te&apos;st\" alt=\"jpg\">hel&apos;lo</b>", OnString::escapeSingleTickInHtml("<b src='gif' title=\"te'st\" alt=\"jpg\">hel'lo</b>"));
}
}
\ 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