Commit 4f52831e authored by Carsten  Rose's avatar Carsten Rose
Browse files

Refs #7743. Detection of 'pattern error' on per QFQ default, custom instance...

Refs #7743. Detection of 'pattern error' on per QFQ default, custom instance wide, per form or per FormElement - per FormElement overwrites other. System specific generated overwrites QFQ static default, instance wide default. Move default pattern to constants.
parent 8c117f3c
Pipeline #1413 passed with stage
in 2 minutes and 22 seconds
...@@ -89,6 +89,15 @@ const SANITIZE_EMPTY_STRING = 'empty string'; ...@@ -89,6 +89,15 @@ const SANITIZE_EMPTY_STRING = 'empty string';
const SANITIZE_VIOLATE = '!!'; const SANITIZE_VIOLATE = '!!';
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,}$';
const PATTERN_ALLBUT = '^[^\[\]{}%\\\\#]*$';
const PATTERN_ALL = '.*';
// Index wrap setup table // Index wrap setup table
const WRAP_SETUP_TITLE = 'title'; const WRAP_SETUP_TITLE = 'title';
const WRAP_SETUP_ELEMENT = 'element'; const WRAP_SETUP_ELEMENT = 'element';
...@@ -167,13 +176,13 @@ const ERROR_PATTERN_VIOLATION = 1043; ...@@ -167,13 +176,13 @@ const ERROR_PATTERN_VIOLATION = 1043;
const ERROR_RECORDID_0_FORBIDDEN = 1044; const ERROR_RECORDID_0_FORBIDDEN = 1044;
const ERROR_LOG_NOT_WRITABLE = 1045; const ERROR_LOG_NOT_WRITABLE = 1045;
const ERROR_UNNOWN_STORE = 1046; const ERROR_UNNOWN_STORE = 1046;
const ERROR_GET_STORE_ZERO = 1047; const ERROR_GET_INVALID_STORE = 1047;
const ERROR_SET_STORE_ZERO = 1048; const ERROR_SET_STORE_ZERO = 1048;
const ERROR_INVALID_OR_MISSING_PARAMETER = 1050; const ERROR_INVALID_OR_MISSING_PARAMETER = 1050;
const ERROR_UNKNOWN_SQL_LOG_MODE = 1051; const ERROR_UNKNOWN_SQL_LOG_MODE = 1051;
const ERROR_FORM_NOT_FOUND = 1052; const ERROR_FORM_NOT_FOUND = 1052;
const ERROR_DATE_TIME_FORMAT_NOT_RECOGNISED = 1053; const ERROR_DATE_TIME_FORMAT_NOT_RECOGNISED = 1053;
const ERROR_SANATIZE_INVALID_VALUE = 1054; const ERROR_SANITIZE_INVALID_VALUE = 1054;
const ERROR_REQUIRED_VALUE_EMPTY = 1055; const ERROR_REQUIRED_VALUE_EMPTY = 1055;
const ERROR_DATE_UNEXPECTED_FORMAT = 1056; const ERROR_DATE_UNEXPECTED_FORMAT = 1056;
const ERROR_UNEXPECTED_TYPE = 1057; const ERROR_UNEXPECTED_TYPE = 1057;
...@@ -886,6 +895,8 @@ const F_RECORD_LOCK_TIMEOUT_SECONDS = SYSTEM_RECORD_LOCK_TIMEOUT_SECONDS; ...@@ -886,6 +895,8 @@ const F_RECORD_LOCK_TIMEOUT_SECONDS = SYSTEM_RECORD_LOCK_TIMEOUT_SECONDS;
const F_SESSION_TIMEOUT_SECONDS = SYSTEM_SESSION_TIMEOUT_SECONDS; const F_SESSION_TIMEOUT_SECONDS = SYSTEM_SESSION_TIMEOUT_SECONDS;
const F_FE_DATA_PATTERN_ERROR = 'data-pattern-error'; const F_FE_DATA_PATTERN_ERROR = 'data-pattern-error';
const F_FE_DATA_PATTERN_ERROR_SYSTEM = 'data-pattern-error-system'; // only used to determine final text
const F_FE_DATA_REQUIRED_ERROR = 'data-required-error'; const F_FE_DATA_REQUIRED_ERROR = 'data-required-error';
const F_FE_DATA_MATCH_ERROR = 'data-match-error'; // contains id of the sibling input to check that i const F_FE_DATA_MATCH_ERROR = 'data-match-error'; // contains id of the sibling input to check that i
const F_FE_DATA_ERROR = 'data-error'; const F_FE_DATA_ERROR = 'data-error';
......
...@@ -901,6 +901,7 @@ class QuickFormQuery { ...@@ -901,6 +901,7 @@ class QuickFormQuery {
} else { } else {
$form[F_DB_INDEX] = $this->evaluate->parse($form[F_DB_INDEX]); $form[F_DB_INDEX] = $this->evaluate->parse($form[F_DB_INDEX]);
} }
if (empty($form[F_PRIMARY_KEY])) { if (empty($form[F_PRIMARY_KEY])) {
$form[F_PRIMARY_KEY] = F_PRIMARY_KEY_DEFAULT; $form[F_PRIMARY_KEY] = F_PRIMARY_KEY_DEFAULT;
} }
...@@ -1221,6 +1222,8 @@ class QuickFormQuery { ...@@ -1221,6 +1222,8 @@ class QuickFormQuery {
FE_INPUT_EXTRA_BUTTON_INFO_CLASS, FE_INPUT_EXTRA_BUTTON_INFO_CLASS,
F_SHOW_ID_IN_FORM_TITLE, F_SHOW_ID_IN_FORM_TITLE,
F_FE_DATA_PATTERN_ERROR_SYSTEM, // Not a classical element to overwrite by form definition, but should be copied to detect changes per custom setting.
]; ];
// By definition: existing vars which are empty, means: EMPTY - do not use any default! // By definition: existing vars which are empty, means: EMPTY - do not use any default!
...@@ -1235,13 +1238,15 @@ class QuickFormQuery { ...@@ -1235,13 +1238,15 @@ class QuickFormQuery {
$formSpec[F_FE_LABEL_ALIGN] = $this->store->getVar(SYSTEM_LABEL_ALIGN, STORE_SYSTEM . STORE_EMPTY); $formSpec[F_FE_LABEL_ALIGN] = $this->store->getVar(SYSTEM_LABEL_ALIGN, STORE_SYSTEM . STORE_EMPTY);
} }
$storeSystem=$this->store::getStore(STORE_SYSTEM);
foreach ($keys as $key) { foreach ($keys as $key) {
if (isset($formSpec[$key])) { if (isset($formSpec[$key])) {
$this->store->setVar($key, $formSpec[$key], STORE_SYSTEM); $this->store->setVar($key, $formSpec[$key], STORE_SYSTEM);
} else { } else {
// if not found set '' // if not found set ''
$formSpec[$key] = $this->store->getVar($key, STORE_SYSTEM . STORE_EMPTY); $formSpec[$key] = $storeSystem[$key]??'';
} }
} }
......
...@@ -254,6 +254,9 @@ class HelperFormElement { ...@@ -254,6 +254,9 @@ class HelperFormElement {
// Iterate over all FormElement // Iterate over all FormElement
foreach ($feSpecNative as $key => $element) { foreach ($feSpecNative as $key => $element) {
$feSpecNative[$key][F_FE_DATA_PATTERN_ERROR_SYSTEM] = $formSpec[F_FE_DATA_PATTERN_ERROR_SYSTEM];
Support::setIfNotSet($feSpecNative[$key], F_FE_DATA_PATTERN_ERROR, $formSpec[F_FE_DATA_PATTERN_ERROR]); Support::setIfNotSet($feSpecNative[$key], F_FE_DATA_PATTERN_ERROR, $formSpec[F_FE_DATA_PATTERN_ERROR]);
Support::setIfNotSet($feSpecNative[$key], F_FE_DATA_REQUIRED_ERROR, $formSpec[F_FE_DATA_REQUIRED_ERROR]); Support::setIfNotSet($feSpecNative[$key], F_FE_DATA_REQUIRED_ERROR, $formSpec[F_FE_DATA_REQUIRED_ERROR]);
Support::setIfNotSet($feSpecNative[$key], F_FE_DATA_MATCH_ERROR, $formSpec[F_FE_DATA_MATCH_ERROR]); Support::setIfNotSet($feSpecNative[$key], F_FE_DATA_MATCH_ERROR, $formSpec[F_FE_DATA_MATCH_ERROR]);
......
...@@ -23,13 +23,13 @@ require_once(__DIR__ . '/../../core/Constants.php'); ...@@ -23,13 +23,13 @@ require_once(__DIR__ . '/../../core/Constants.php');
class Sanitize { class Sanitize {
private static $sanitizePattern = [ private static $sanitizePattern = [
SANITIZE_ALLOW_ALNUMX => '^[@\-_\.,;: \/\(\)a-zA-Z0-9ÀÈÌÒÙàèìòùÁÉÍÓÚÝáéíóúýÂÊÎÔÛâêîôûÃÑÕãñõÄËÏÖÜŸäëïöüÿç]*$', // ':alnum:' does not work here in FF SANITIZE_ALLOW_ALNUMX => PATTERN_ALNUMX, // ':alnum:' does not work here in FF
SANITIZE_ALLOW_DIGIT => '^[\d]*$', SANITIZE_ALLOW_DIGIT => PATTERN_DIGIT,
SANITIZE_ALLOW_NUMERICAL => '^[\d.+-]*$', SANITIZE_ALLOW_NUMERICAL => PATTERN_NUMERICAL,
SANITIZE_ALLOW_EMAIL => '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', SANITIZE_ALLOW_EMAIL => PATTERN_EMAIL,
SANITIZE_ALLOW_ALLBUT => PATTERN_ALLBUT,
SANITIZE_ALLOW_ALL => PATTERN_ALL,
SANITIZE_ALLOW_PATTERN => '', SANITIZE_ALLOW_PATTERN => '',
SANITIZE_ALLOW_ALLBUT => '^[^\[\]{}%\\\\#]*$',
SANITIZE_ALLOW_ALL => '.*',
]; ];
private static $sanitizeMessage = [ private static $sanitizeMessage = [
...@@ -37,9 +37,9 @@ class Sanitize { ...@@ -37,9 +37,9 @@ class Sanitize {
SANITIZE_ALLOW_DIGIT => 'Allowed characters: 0...9', SANITIZE_ALLOW_DIGIT => 'Allowed characters: 0...9',
SANITIZE_ALLOW_NUMERICAL => 'Allowed characters: 0...9 and .+-', SANITIZE_ALLOW_NUMERICAL => 'Allowed characters: 0...9 and .+-',
SANITIZE_ALLOW_EMAIL => 'Requested format: string@domain.tld', SANITIZE_ALLOW_EMAIL => 'Requested format: string@domain.tld',
SANITIZE_ALLOW_PATTERN => 'Please match the requested format',
SANITIZE_ALLOW_ALLBUT => 'Forbidden characters: ^[]{}%\#', SANITIZE_ALLOW_ALLBUT => 'Forbidden characters: ^[]{}%\#',
SANITIZE_ALLOW_ALL => '', SANITIZE_ALLOW_ALL => '',
SANITIZE_ALLOW_PATTERN => 'Please match the requested format',
]; ];
...@@ -56,13 +56,14 @@ class Sanitize { ...@@ -56,13 +56,14 @@ class Sanitize {
* @param string $pattern Pattern as regexp * @param string $pattern Pattern as regexp
* @param string $decimalFormat with 'size,precision' * @param string $decimalFormat with 'size,precision'
* @param string $mode SANITIZE_EXCEPTION | SANITIZE_EMPTY_STRING * @param string $mode SANITIZE_EXCEPTION | SANITIZE_EMPTY_STRING
* @param string $dataPatternErrorText
* @return string * @return string
* @throws CodeException * @throws CodeException
* @throws UserFormException * @throws UserFormException
*/ */
public static function sanitize($value, $sanitizeClass = SANITIZE_DEFAULT, $pattern = '', $decimalFormat = '', $mode = SANITIZE_EMPTY_STRING) { public static function sanitize($value, $sanitizeClass = SANITIZE_DEFAULT, $pattern = '', $decimalFormat = '', $mode = SANITIZE_EMPTY_STRING, $dataPatternErrorText = '') {
$pattern = self::getInputCheckPattern($sanitizeClass, $pattern, $decimalFormat, $dummy); $pattern = self::getInputCheckPattern($sanitizeClass, $pattern, $decimalFormat, $sanitizeMessage);
// Pattern check // Pattern check
if ($pattern === '' || preg_match("/$pattern/", $value) === 1) { if ($pattern === '' || preg_match("/$pattern/", $value) === 1) {
...@@ -72,7 +73,18 @@ class Sanitize { ...@@ -72,7 +73,18 @@ class Sanitize {
// check failed // check failed
if ($mode === SANITIZE_EXCEPTION) { if ($mode === SANITIZE_EXCEPTION) {
$errorCode = ERROR_PATTERN_VIOLATION; $errorCode = ERROR_PATTERN_VIOLATION;
$errorText = "Value '$value' violates checkrule " . $sanitizeClass . " with pattern '$pattern'.";
// Depending on default regexp & custom data-pattern-error, define error text.
if ($dataPatternErrorText == '') {
if ($sanitizeMessage == '') {
$errorText = "Value '$value' violates check rule " . $sanitizeClass . " with pattern '$pattern'.";
} else {
$errorText = $sanitizeMessage;
}
} else {
$errorText = $dataPatternErrorText;
}
throw new UserFormException($errorText, $errorCode); throw new UserFormException($errorText, $errorCode);
} }
...@@ -81,7 +93,7 @@ class Sanitize { ...@@ -81,7 +93,7 @@ class Sanitize {
/** /**
* Returns the final validation pattern based on a given $checkType, $pattern, and $decimalFormat * Returns the final validation pattern based on a given $checkType, $pattern, and $decimalFormat
* @param string $checkType * @param string $checkType SANITIZE_DEFAULT, ...
* @param string $pattern * @param string $pattern
* @param string $decimalFormat e.g. "10,2" * @param string $decimalFormat e.g. "10,2"
* *
...@@ -89,7 +101,9 @@ class Sanitize { ...@@ -89,7 +101,9 @@ class Sanitize {
* @return string * @return string
* @throws CodeException * @throws CodeException
*/ */
public static function getInputCheckPattern($checkType = SANITIZE_DEFAULT, $pattern = '', $decimalFormat = '', &$rcSanitizeMessage) { public static function getInputCheckPattern($checkType, $pattern, $decimalFormat, &$rcSanitizeMessage) {
$rcSanitizeMessage = self::$sanitizeMessage[$checkType] ?? '';
switch ($checkType) { switch ($checkType) {
case SANITIZE_ALLOW_PATTERN: case SANITIZE_ALLOW_PATTERN:
...@@ -111,8 +125,6 @@ class Sanitize { ...@@ -111,8 +125,6 @@ class Sanitize {
throw new CodeException("Unknown checkType: " . $checkType, ERROR_UNKNOWN_CHECKTYPE); throw new CodeException("Unknown checkType: " . $checkType, ERROR_UNKNOWN_CHECKTYPE);
} }
$rcSanitizeMessage = self::$sanitizeMessage[$checkType];
// decimalFormat // decimalFormat
if ($decimalFormat != '' && $checkType !== SANITIZE_ALLOW_DIGIT) { if ($decimalFormat != '' && $checkType !== SANITIZE_ALLOW_DIGIT) {
// overwrite pattern with decimalFormat pattern // overwrite pattern with decimalFormat pattern
...@@ -252,7 +264,6 @@ class Sanitize { ...@@ -252,7 +264,6 @@ class Sanitize {
return $item; return $item;
} }
/** /**
* Check a given $_GET[$key] is digit. * Check a given $_GET[$key] is digit.
......
...@@ -204,12 +204,13 @@ class Support { ...@@ -204,12 +204,13 @@ class Support {
/** /**
* Format's an attribute: $type=$value. If $flagOmitEmpty==true && $value=='': return ''. * Format's an attribute: $type=$value. If $flagOmitEmpty==true && $value=='': return ''.
* Escape double tick - assumes that attributes will always be enclosed by double ticks.
* Add's a space at the end. * Add's a space at the end.
* *
* @param string $type * @param string $type
* @param string|array $value * @param string|array $value
* @param bool $flagOmitEmpty * @param bool $flagOmitEmpty true|false
* @param string $modeEscape * @param string $modeEscape ESCAPE_WITH_BACKSLASH | ESCAPE_WITH_HTML_QUOTE
* *
* @return string correctly formatted attribute. Space at the end. * @return string correctly formatted attribute. Space at the end.
* @throws CodeException * @throws CodeException
...@@ -798,7 +799,7 @@ class Support { ...@@ -798,7 +799,7 @@ class Support {
self::setIfNotSet($formElement, FE_HTML_BEFORE); self::setIfNotSet($formElement, FE_HTML_BEFORE);
self::setIfNotSet($formElement, FE_HTML_AFTER); self::setIfNotSet($formElement, FE_HTML_AFTER);
self::setIfNotSet($formElement, FE_DATA_REFERENCE, ($formElement[FE_NAME]=='' ? $formElement[FE_ID] : $formElement[FE_NAME]) ); self::setIfNotSet($formElement, FE_DATA_REFERENCE, ($formElement[FE_NAME] == '' ? $formElement[FE_ID] : $formElement[FE_NAME]));
self::setIfNotSet($formElement, FE_SUBRECORD_TABLE_CLASS, SUBRECORD_TABLE_CLASS_DEFAULT); self::setIfNotSet($formElement, FE_SUBRECORD_TABLE_CLASS, SUBRECORD_TABLE_CLASS_DEFAULT);
...@@ -965,12 +966,12 @@ class Support { ...@@ -965,12 +966,12 @@ class Support {
} }
// If nothing given, set default // If nothing given, set default
if ( $formElement[FE_MIN]=='' ){ if ($formElement[FE_MIN] == '') {
$formElement[FE_MIN] = $min; $formElement[FE_MIN] = $min;
} }
// If nothing given, set default // If nothing given, set default
if ( $formElement[FE_MAX]==''){ if ($formElement[FE_MAX] == '') {
$formElement[FE_MAX] = $max; $formElement[FE_MAX] = $max;
} }
...@@ -989,8 +990,8 @@ class Support { ...@@ -989,8 +990,8 @@ class Support {
} }
// If min or max is set and if there is the standard error text given, define a more detailed error text if the value is outside. // If min or max is set and if there is the standard error text given, define a more detailed error text if the value is outside.
if( ($formElement[FE_MIN]!='' ||$formElement[FE_MAX]!='') && $formElement[F_FE_DATA_ERROR]==F_FE_DATA_ERROR_DEFAULT ){ if (($formElement[FE_MIN] != '' || $formElement[FE_MAX] != '') && ($formElement[F_FE_DATA_ERROR]??'') == F_FE_DATA_ERROR_DEFAULT) {
$formElement[F_FE_DATA_ERROR]=F_FE_DATA_ERROR_DEFAULT . ' - value to low / high'; $formElement[F_FE_DATA_ERROR] = F_FE_DATA_ERROR_DEFAULT . ' - allowed values: ' . $formElement[FE_MIN] . '...' . $formElement[FE_MAX];
} }
} }
...@@ -1268,7 +1269,7 @@ class Support { ...@@ -1268,7 +1269,7 @@ class Support {
} else { } else {
throw new UserFormException(json_encode( throw new UserFormException(json_encode(
[ERROR_MESSAGE_TO_USER => 'Copy upload failed - file already exist', [ERROR_MESSAGE_TO_USER => 'Copy upload failed - file already exist',
ERROR_MESSAGE_SUPPORT => 'File: ' .$pathFileName]), ERROR_IO_FILE_EXIST); ERROR_MESSAGE_SUPPORT => 'File: ' . $pathFileName]), ERROR_IO_FILE_EXIST);
} }
} }
......
...@@ -148,6 +148,9 @@ class Config { ...@@ -148,6 +148,9 @@ class Config {
self::checkForAttack($config); self::checkForAttack($config);
// Copy values to detect custom settings later
$config[F_FE_DATA_PATTERN_ERROR_SYSTEM]=$config[F_FE_DATA_PATTERN_ERROR];
return $config; return $config;
} }
...@@ -356,6 +359,7 @@ class Config { ...@@ -356,6 +359,7 @@ class Config {
F_FE_DATA_REQUIRED_ERROR => F_FE_DATA_REQUIRED_ERROR_DEFAULT, F_FE_DATA_REQUIRED_ERROR => F_FE_DATA_REQUIRED_ERROR_DEFAULT,
F_FE_DATA_MATCH_ERROR => F_FE_DATA_MATCH_ERROR_DEFAULT, F_FE_DATA_MATCH_ERROR => F_FE_DATA_MATCH_ERROR_DEFAULT,
F_FE_DATA_ERROR => F_FE_DATA_ERROR_DEFAULT, F_FE_DATA_ERROR => F_FE_DATA_ERROR_DEFAULT,
F_FE_DATA_PATTERN_ERROR => F_FE_DATA_PATTERN_ERROR_DEFAULT,
SYSTEM_FLAG_PRODUCTION => 'yes', SYSTEM_FLAG_PRODUCTION => 'yes',
SYSTEM_THROW_GENERAL_ERROR => 'auto', SYSTEM_THROW_GENERAL_ERROR => 'auto',
......
...@@ -308,7 +308,7 @@ class FillStoreForm { ...@@ -308,7 +308,7 @@ class FillStoreForm {
// Check only if there is something. // Check only if there is something.
if ($val !== '' && $formMode != FORM_UPDATE && $formElement[FE_MODE] != FE_MODE_HIDDEN) { if ($val !== '' && $formMode != FORM_UPDATE && $formElement[FE_MODE] != FE_MODE_HIDDEN) {
$val = Sanitize::sanitize($val, $formElement[FE_CHECK_TYPE], $formElement[FE_CHECK_PATTERN], $val = Sanitize::sanitize($val, $formElement[FE_CHECK_TYPE], $formElement[FE_CHECK_PATTERN],
$formElement[FE_DECIMAL_FORMAT], SANITIZE_EXCEPTION); $formElement[FE_DECIMAL_FORMAT], SANITIZE_EXCEPTION, $formElement[F_FE_DATA_PATTERN_ERROR]??'');
if ($formElement[FE_ENCODE] === FE_ENCODE_SPECIALCHAR) { if ($formElement[FE_ENCODE] === FE_ENCODE_SPECIALCHAR) {
// $val = htmlspecialchars($val, ENT_QUOTES); // $val = htmlspecialchars($val, ENT_QUOTES);
......
...@@ -423,7 +423,7 @@ class Store { ...@@ -423,7 +423,7 @@ class Store {
/** /**
* Returns a complete $store. * Returns a complete $store.
* *
* @param $store * @param string $store STORE_SYSTEM, ...
* *
* @return array * @return array
* @throws UserFormException * @throws UserFormException
...@@ -432,13 +432,13 @@ class Store { ...@@ -432,13 +432,13 @@ class Store {
public static function getStore($store) { public static function getStore($store) {
$vars = array(); $vars = array();
// Check valid Storename // Check valid store name
if (!isset(self::$sanitizeStore[$store])) { if (!isset(self::$sanitizeStore[$store])) {
throw new UserFormException("Unknown Store: $store", ERROR_UNNOWN_STORE); throw new UserFormException("Unknown Store: $store", ERROR_UNNOWN_STORE);
} }
if ($store === STORE_ZERO) { if ($store === STORE_ZERO || $store === STORE_EMPTY) {
throw new CodeException("getStore() for STORE_ZERO is impossible - there are no values saved.", ERROR_GET_STORE_ZERO); throw new CodeException("getStore() for $store is impossible - there are no values saved.", ERROR_GET_INVALID_STORE);
} }
if (isset(self::$raw[$store])) { if (isset(self::$raw[$store])) {
......
...@@ -95,38 +95,38 @@ class BuildFormPlainTest extends AbstractDatabaseTest { ...@@ -95,38 +95,38 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
$label['123-r'][API_ELEMENT_ATTRIBUTE] = ['class' => '']; $label['123-r'][API_ELEMENT_ATTRIBUTE] = ['class' => ''];
$result = $build->buildInput($formElement, 'name:1', '', $json); $result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-pattern-error="pattern error" data-required-error="data required" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result); $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-pattern-error="pattern error" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT . '" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json); $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
// Min/Max // Min/Max
$formElement[FE_MIN] = '1'; $formElement[FE_MIN] = '1';
$formElement[FE_MAX] = '10'; $formElement[FE_MAX] = '10';
$result = $build->buildInput($formElement, 'name:1', '', $json); $result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="number" value="" data-pattern-error="pattern error" data-required-error="data required" min="1" max="10" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result); $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="number" value="" data-pattern-error="pattern error" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT . '" data-error="Error" min="1" max="10" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json); $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
$formElement[FE_MIN] = '1'; $formElement[FE_MIN] = '1';
$formElement[FE_MAX] = ''; $formElement[FE_MAX] = '';
$result = $build->buildInput($formElement, 'name:1', '', $json); $result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-pattern-error="pattern error" data-required-error="data required" min="1" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result); $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-pattern-error="pattern error" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT . '" data-error="Error" min="1" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json); $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
$formElement[FE_MIN] = ''; $formElement[FE_MIN] = '';
$formElement[FE_MAX] = '10'; $formElement[FE_MAX] = '10';
$result = $build->buildInput($formElement, 'name:1', '', $json); $result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-pattern-error="pattern error" data-required-error="data required" max="10" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result); $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-pattern-error="pattern error" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT . '" data-error="Error" max="10" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json); $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
$formElement[FE_MIN] = '0'; $formElement[FE_MIN] = '0';
$formElement[FE_MAX] = '10'; $formElement[FE_MAX] = '10';
$result = $build->buildInput($formElement, 'name:1', '', $json); $result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-pattern-error="pattern error" data-required-error="data required" min="0" max="10" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result); $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-pattern-error="pattern error" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT . '" data-error="Error" min="0" max="10" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json); $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
$formElement[FE_MIN] = '-5'; $formElement[FE_MIN] = '-5';
$formElement[FE_MAX] = '0'; $formElement[FE_MAX] = '0';
$result = $build->buildInput($formElement, 'name:1', '', $json); $result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-pattern-error="pattern error" data-required-error="data required" min="-5" max="0" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result); $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" data-pattern-error="pattern error" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT . '" data-error="Error" min="-5" max="0" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json); $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
// reset so they don't interfere with next tests // reset so they don't interfere with next tests
...@@ -137,14 +137,14 @@ class BuildFormPlainTest extends AbstractDatabaseTest { ...@@ -137,14 +137,14 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
$formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_PATTERN; $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_PATTERN;
$formElement[FE_CHECK_PATTERN] = '^[a-z]*$'; $formElement[FE_CHECK_PATTERN] = '^[a-z]*$';
$result = $build->buildInput($formElement, 'name:1', '', $json); $result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="^[a-z]*$" data-pattern-error="pattern error" data-required-error="data required" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result); $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="^[a-z]*$" data-pattern-error="pattern error" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT . '" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
$label['123'][API_ELEMENT_ATTRIBUTE]['pattern'] = '^[a-z]*$'; $label['123'][API_ELEMENT_ATTRIBUTE]['pattern'] = '^[a-z]*$';
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json); $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
$formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_DIGIT; $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_DIGIT;
$formElement[FE_CHECK_PATTERN] = ''; $formElement[FE_CHECK_PATTERN] = '';
$result = $build->buildInput($formElement, 'name:1', '', $json); $result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="^[\d]*$" data-pattern-error="Allowed characters: 0...9" data-required-error="data required" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result); $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="^[\d]*$" data-pattern-error="pattern error" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT . '" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
$label['123'][API_ELEMENT_ATTRIBUTE]['pattern'] = '^[\d]*$'; $label['123'][API_ELEMENT_ATTRIBUTE]['pattern'] = '^[\d]*$';
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json); $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
...@@ -153,7 +153,7 @@ class BuildFormPlainTest extends AbstractDatabaseTest { ...@@ -153,7 +153,7 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
$formElement[FE_CHECK_PATTERN] = ''; $formElement[FE_CHECK_PATTERN] = '';
$result = $build->buildInput($formElement, 'name:1', '', $json); $result = $build->buildInput($formElement, 'name:1', '', $json);
$label['123'][API_ELEMENT_ATTRIBUTE]['pattern'] = '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'; $label['123'][API_ELEMENT_ATTRIBUTE]['pattern'] = '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$';
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$" data-pattern-error="Requested format: string@domain.tld" data-required-error="data required" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result); $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$" data-pattern-error="pattern error" data-required-error="data required" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json); $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
$formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALL; $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALL;
...@@ -163,7 +163,7 @@ class BuildFormPlainTest extends AbstractDatabaseTest { ...@@ -163,7 +163,7 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
// Decimal format // Decimal format
$formElement[FE_DECIMAL_FORMAT] = '5,2'; $formElement[FE_DECIMAL_FORMAT] = '5,2';
$result = $build->buildInput($formElement, 'name:1', '', $json); $result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="^-?[0-9]{0,3}(\.[0-9]{0,2})?$" data-pattern-error="Requested decimal format (mantis,decimal): 5,2" data-required-error="data required" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result); $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="^-?[0-9]{0,3}(\.[0-9]{0,2})?$" data-pattern-error="pattern error" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT . '" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
$label['123'][API_ELEMENT_ATTRIBUTE]['pattern'] = '^-?[0-9]{0,3}(\.[0-9]{0,2})?$'; $label['123'][API_ELEMENT_ATTRIBUTE]['pattern'] = '^-?[0-9]{0,3}(\.[0-9]{0,2})?$';
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json); $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
...@@ -174,14 +174,14 @@ class BuildFormPlainTest extends AbstractDatabaseTest { ...@@ -174,14 +174,14 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
$formElement['size'] = 40; $formElement['size'] = 40;
$formElement['maxLength'] = 40; $formElement['maxLength'] = 40;
$result = $build->buildInput($formElement, 'name:1', '', $json); $result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="40" type="input" size="40" value="" data-pattern-error="pattern error" data-required-error="data required" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result); $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="40" type="input" size="40" value="" data-pattern-error="pattern error" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT . '" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
unset($label['123'][API_ELEMENT_ATTRIBUTE]['pattern']); unset($label['123'][API_ELEMENT_ATTRIBUTE]['pattern']);
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json); $this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);