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';
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
const WRAP_SETUP_TITLE = 'title';
const WRAP_SETUP_ELEMENT = 'element';
......@@ -167,13 +176,13 @@ const ERROR_PATTERN_VIOLATION = 1043;
const ERROR_RECORDID_0_FORBIDDEN = 1044;
const ERROR_LOG_NOT_WRITABLE = 1045;
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_INVALID_OR_MISSING_PARAMETER = 1050;
const ERROR_UNKNOWN_SQL_LOG_MODE = 1051;
const ERROR_FORM_NOT_FOUND = 1052;
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_DATE_UNEXPECTED_FORMAT = 1056;
const ERROR_UNEXPECTED_TYPE = 1057;
......@@ -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_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_MATCH_ERROR = 'data-match-error'; // contains id of the sibling input to check that i
const F_FE_DATA_ERROR = 'data-error';
......
......@@ -901,6 +901,7 @@ class QuickFormQuery {
} else {
$form[F_DB_INDEX] = $this->evaluate->parse($form[F_DB_INDEX]);
}
if (empty($form[F_PRIMARY_KEY])) {
$form[F_PRIMARY_KEY] = F_PRIMARY_KEY_DEFAULT;
}
......@@ -1221,6 +1222,8 @@ class QuickFormQuery {
FE_INPUT_EXTRA_BUTTON_INFO_CLASS,
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!
......@@ -1235,13 +1238,15 @@ class QuickFormQuery {
$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) {
if (isset($formSpec[$key])) {
$this->store->setVar($key, $formSpec[$key], STORE_SYSTEM);
} else {
// if not found set ''
$formSpec[$key] = $this->store->getVar($key, STORE_SYSTEM . STORE_EMPTY);
$formSpec[$key] = $storeSystem[$key]??'';
}
}
......
......@@ -254,6 +254,9 @@ class HelperFormElement {
// Iterate over all FormElement
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_REQUIRED_ERROR, $formSpec[F_FE_DATA_REQUIRED_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');
class Sanitize {
private static $sanitizePattern = [
SANITIZE_ALLOW_ALNUMX => '^[@\-_\.,;: \/\(\)a-zA-Z0-9ÀÈÌÒÙàèìòùÁÉÍÓÚÝáéíóúýÂÊÎÔÛâêîôûÃÑÕãñõÄËÏÖÜŸäëïöüÿç]*$', // ':alnum:' does not work here in FF
SANITIZE_ALLOW_DIGIT => '^[\d]*$',
SANITIZE_ALLOW_NUMERICAL => '^[\d.+-]*$',
SANITIZE_ALLOW_EMAIL => '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
SANITIZE_ALLOW_ALNUMX => PATTERN_ALNUMX, // ':alnum:' does not work here in FF
SANITIZE_ALLOW_DIGIT => PATTERN_DIGIT,
SANITIZE_ALLOW_NUMERICAL => PATTERN_NUMERICAL,
SANITIZE_ALLOW_EMAIL => PATTERN_EMAIL,
SANITIZE_ALLOW_ALLBUT => PATTERN_ALLBUT,
SANITIZE_ALLOW_ALL => PATTERN_ALL,
SANITIZE_ALLOW_PATTERN => '',
SANITIZE_ALLOW_ALLBUT => '^[^\[\]{}%\\\\#]*$',
SANITIZE_ALLOW_ALL => '.*',
];
private static $sanitizeMessage = [
......@@ -37,9 +37,9 @@ class Sanitize {
SANITIZE_ALLOW_DIGIT => 'Allowed characters: 0...9',
SANITIZE_ALLOW_NUMERICAL => 'Allowed characters: 0...9 and .+-',
SANITIZE_ALLOW_EMAIL => 'Requested format: string@domain.tld',
SANITIZE_ALLOW_PATTERN => 'Please match the requested format',
SANITIZE_ALLOW_ALLBUT => 'Forbidden characters: ^[]{}%\#',
SANITIZE_ALLOW_ALL => '',
SANITIZE_ALLOW_PATTERN => 'Please match the requested format',
];
......@@ -56,13 +56,14 @@ class Sanitize {
* @param string $pattern Pattern as regexp
* @param string $decimalFormat with 'size,precision'
* @param string $mode SANITIZE_EXCEPTION | SANITIZE_EMPTY_STRING
* @param string $dataPatternErrorText
* @return string
* @throws CodeException
* @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
if ($pattern === '' || preg_match("/$pattern/", $value) === 1) {
......@@ -72,7 +73,18 @@ class Sanitize {
// check failed
if ($mode === SANITIZE_EXCEPTION) {
$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);
}
......@@ -81,7 +93,7 @@ class Sanitize {
/**
* 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 $decimalFormat e.g. "10,2"
*
......@@ -89,7 +101,9 @@ class Sanitize {
* @return string
* @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) {
case SANITIZE_ALLOW_PATTERN:
......@@ -111,8 +125,6 @@ class Sanitize {
throw new CodeException("Unknown checkType: " . $checkType, ERROR_UNKNOWN_CHECKTYPE);
}
$rcSanitizeMessage = self::$sanitizeMessage[$checkType];
// decimalFormat
if ($decimalFormat != '' && $checkType !== SANITIZE_ALLOW_DIGIT) {
// overwrite pattern with decimalFormat pattern
......@@ -253,7 +265,6 @@ class Sanitize {
}
/**
* Check a given $_GET[$key] is digit.
* If yes: do nothing
......
......@@ -204,12 +204,13 @@ class Support {
/**
* 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.
*
* @param string $type
* @param string|array $value
* @param bool $flagOmitEmpty
* @param string $modeEscape
* @param bool $flagOmitEmpty true|false
* @param string $modeEscape ESCAPE_WITH_BACKSLASH | ESCAPE_WITH_HTML_QUOTE
*
* @return string correctly formatted attribute. Space at the end.
* @throws CodeException
......@@ -798,7 +799,7 @@ class Support {
self::setIfNotSet($formElement, FE_HTML_BEFORE);
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);
......@@ -965,12 +966,12 @@ class Support {
}
// If nothing given, set default
if ( $formElement[FE_MIN]=='' ){
if ($formElement[FE_MIN] == '') {
$formElement[FE_MIN] = $min;
}
// If nothing given, set default
if ( $formElement[FE_MAX]==''){
if ($formElement[FE_MAX] == '') {
$formElement[FE_MAX] = $max;
}
......@@ -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( ($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';
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 . ' - allowed values: ' . $formElement[FE_MIN] . '...' . $formElement[FE_MAX];
}
}
......@@ -1268,7 +1269,7 @@ class Support {
} else {
throw new UserFormException(json_encode(
[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 {
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;
}
......@@ -356,6 +359,7 @@ class Config {
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_ERROR => F_FE_DATA_ERROR_DEFAULT,
F_FE_DATA_PATTERN_ERROR => F_FE_DATA_PATTERN_ERROR_DEFAULT,
SYSTEM_FLAG_PRODUCTION => 'yes',
SYSTEM_THROW_GENERAL_ERROR => 'auto',
......
......@@ -308,7 +308,7 @@ class FillStoreForm {
// Check only if there is something.
if ($val !== '' && $formMode != FORM_UPDATE && $formElement[FE_MODE] != FE_MODE_HIDDEN) {
$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) {
// $val = htmlspecialchars($val, ENT_QUOTES);
......
......@@ -423,7 +423,7 @@ class Store {
/**
* Returns a complete $store.
*
* @param $store
* @param string $store STORE_SYSTEM, ...
*
* @return array
* @throws UserFormException
......@@ -432,13 +432,13 @@ class Store {
public static function getStore($store) {
$vars = array();
// Check valid Storename
// Check valid store name
if (!isset(self::$sanitizeStore[$store])) {
throw new UserFormException("Unknown Store: $store", ERROR_UNNOWN_STORE);
}
if ($store === STORE_ZERO) {
throw new CodeException("getStore() for STORE_ZERO is impossible - there are no values saved.", ERROR_GET_STORE_ZERO);
if ($store === STORE_ZERO || $store === STORE_EMPTY) {
throw new CodeException("getStore() for $store is impossible - there are no values saved.", ERROR_GET_INVALID_STORE);
}
if (isset(self::$raw[$store])) {
......
......@@ -95,38 +95,38 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
$label['123-r'][API_ELEMENT_ATTRIBUTE] = ['class' => ''];
$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);
// Min/Max
$formElement[FE_MIN] = '1';
$formElement[FE_MAX] = '10';
$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);
$formElement[FE_MIN] = '1';
$formElement[FE_MAX] = '';
$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);
$formElement[FE_MIN] = '';
$formElement[FE_MAX] = '10';
$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);
$formElement[FE_MIN] = '0';
$formElement[FE_MAX] = '10';
$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);
$formElement[FE_MIN] = '-5';
$formElement[FE_MAX] = '0';
$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);
// reset so they don't interfere with next tests
......@@ -137,14 +137,14 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
$formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_PATTERN;
$formElement[FE_CHECK_PATTERN] = '^[a-z]*$';
$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]*$';
$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_PATTERN] = '';
$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]*$';
$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 {
$formElement[FE_CHECK_PATTERN] = '';
$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,}$';
$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);
$formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALL;
......@@ -163,7 +163,7 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
// Decimal format
$formElement[FE_DECIMAL_FORMAT] = '5,2';
$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})?$';
$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 {
$formElement['size'] = 40;
$formElement['maxLength'] = 40;
$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']);
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
// maxlength bigger than physical spec:
$formElement['maxLength'] = 1000;
$result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="1000" 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="1000" 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);
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => '', API_ELEMENT_UPDATE => $label], $json);
// no size, no maxlength and column not in primary table
......@@ -190,24 +190,24 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
$formElement2['size'] = '';
$formElement2['name'] = 'specialname';
$result = $build->buildInput($formElement2, 'specialname:1', '', $json);
$this->assertEquals('<input id="123" name="specialname:1" class="form-control" 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="specialname:1" class="form-control" 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);
// no size, given maxlength and column not in primary table
$formElement2['maxLength'] = '10';
$result = $build->buildInput($formElement2, 'specialname:1', '', $json);
$this->assertEquals('<input id="123" name="specialname:1" class="form-control" maxlength="10" 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="specialname:1" class="form-control" maxlength="10" 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);
// size given, no maxlength and column not in primary table
$formElement2['maxLength'] = '';
$formElement2['size'] = '10';
$result = $build->buildInput($formElement2, 'specialname:1', '', $json);
$this->assertEquals('<input id="123" name="specialname:1" class="form-control" type="input" size="10" 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="specialname:1" class="form-control" type="input" size="10" 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);
// size given, maxlength given and column not in primary table
$formElement2['maxLength'] = '20';
$formElement2['size'] = '10';
$result = $build->buildInput($formElement2, 'specialname:1', '', $json);
$this->assertEquals('<input id="123" name="specialname:1" class="form-control" maxlength="20" type="input" size="10" 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="specialname:1" class="form-control" maxlength="20" type="input" size="10" 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);
$formElement2['maxLength'] = '';
$formElement2['size'] = '';
......@@ -215,23 +215,165 @@ class BuildFormPlainTest extends AbstractDatabaseTest {
$formElement2['tooltip'] = 'Nice Tooltip';
$formElement2['placeholder'] = 'Please type a name';
$result = $build->buildInput($formElement2, 'name:1', 'Hello World', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" type="input" value="Hello World" placeholder="Please type a name" data-pattern-error="pattern error" data-required-error="data required" title="Nice Tooltip" 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" type="input" value="Hello World" placeholder="Please type a name" data-pattern-error="pattern error" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT . '" data-error="Error" title="Nice Tooltip" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
$label['123'][API_ELEMENT_ATTRIBUTE] = ['value' => 'Hello World', 'required' => false, 'hidden' => false];
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => 'Hello World', API_ELEMENT_UPDATE => $label], $json);
// textarea
$formElement2['size'] = '40,10';
$result = $build->buildInput($formElement2, 'name:1', 'Hello World', $json);
$this->assertEquals('<textarea id="123" name="name:1" class="form-control" cols="40" rows="10" placeholder="Please type a name" data-pattern-error="pattern error" data-required-error="data required" title="Nice Tooltip" data-hidden="no" data-required="no" >Hello World</textarea><div class="help-block with-errors hidden"></div>', $result);
$this->assertEquals('<textarea id="123" name="name:1" class="form-control" cols="40" rows="10" placeholder="Please type a name" data-pattern-error="pattern error" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT . '" data-error="Error" title="Nice Tooltip" data-hidden="no" data-required="no" >Hello World</textarea><div class="help-block with-errors hidden"></div>', $result);
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => 'Hello World', API_ELEMENT_UPDATE => $label], $json);
$formElement2['size'] = ' 40 , 10 ';
$result = $build->buildInput($formElement2, 'name:1', 'Hello World', $json);
$this->assertEquals('<textarea id="123" name="name:1" class="form-control" cols="40" rows="10" placeholder="Please type a name" data-pattern-error="pattern error" data-required-error="data required" title="Nice Tooltip" data-hidden="no" data-required="no" >Hello World</textarea><div class="help-block with-errors hidden"></div>', $result);
$this->assertEquals('<textarea id="123" name="name:1" class="form-control" cols="40" rows="10" placeholder="Please type a name" data-pattern-error="pattern error" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT . '" data-error="Error" title="Nice Tooltip" data-hidden="no" data-required="no" >Hello World</textarea><div class="help-block with-errors hidden"></div>', $result);
$this->assertEquals(['disabled' => false, FE_MODE_REQUIRED => '', 'form-element' => 'name:1', 'value' => 'Hello World', API_ELEMENT_UPDATE => $label], $json);
}
/**
* @throws CodeException
* @throws UserFormException
* @throws UserReportException
*/
public function testBuildInputPattern() {
$form = array();
$formElement = array();
$json = array();
$this->templateFormNFormElement($form, $formElement);
$build = new BuildFormPlain($form, array(), [$formElement], $this->dbArray);
$formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALL;
$formElement[FE_DECIMAL_FORMAT] = '';
$label['123-l'][API_ELEMENT_CONTENT] = '<label for="name:1" class="control-label" >Name</label>';
$label['123'][API_ELEMENT_ATTRIBUTE] = ['value' => '', 'required' => false, 'hidden' => false];
$label['123-r'][API_ELEMENT_ATTRIBUTE] = ['class' => ''];
$formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALNUMX;
$result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_ALNUMX . '" 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);
$formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_DIGIT;
$result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_DIGIT . '" 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);
$formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_NUMERICAL;
$result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_NUMERICAL . '" 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);
$formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_EMAIL;
$result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_EMAIL . '" 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);
$formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALLBUT;
$result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_ALLBUT . '" 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);
$formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALL;
$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="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT . '" data-error="Error" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
$formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_PATTERN;
$formElement[FE_CHECK_PATTERN] = '^[0-2]$';
$result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . $formElement[FE_CHECK_PATTERN] . '" 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);
}
/**
* @throws CodeException
* @throws UserFormException
* @throws UserReportException
*/
public function testBuildInputPatternErrorText() {
$form = array();
$formElement = array();
$json = array();
$this->templateFormNFormElement($form, $formElement);
$build = new BuildFormPlain($form, array(), [$formElement], $this->dbArray);
$formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALL;
$formElement[FE_DECIMAL_FORMAT] = '';
$label['123-l'][API_ELEMENT_CONTENT] = '<label for="name:1" class="control-label" >Name</label>';
$label['123'][API_ELEMENT_ATTRIBUTE] = ['value' => '', 'required' => false, 'hidden' => false];
$label['123-r'][API_ELEMENT_ATTRIBUTE] = ['class' => ''];
// Defaults data-pattern-error: ALNUMX
$formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALNUMX;
$result = $build->buildInput($formElement, 'name:1', '', $json);
$this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_ALNUMX .
'" data-pattern-error="' . $formElement[F_FE_DATA_PATTERN_ERROR] . '" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT .
'" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
// const SANITIZE_ALLOW_ALNUMX = "alnumx";
// const SANITIZE_ALLOW_DIGIT = "digit";
// const SANITIZE_ALLOW_NUMERICAL = "numerical";
// const SANITIZE_ALLOW_EMAIL = "email";
// const SANITIZE_ALLOW_PATTERN = "pattern";
// const SANITIZE_ALLOW_ALLBUT = "allbut";
// const SANITIZE_ALLOW_ALL = "all";
//
// // Defaults data-pattern-error: DIGIT
// $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_DIGIT;
// $result = $build->buildInput($formElement, 'name:1', '', $json);
// $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_ALNUMX .
// '" data-pattern-error="' . $formElement[F_FE_DATA_PATTERN_ERROR] . '" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT .
// '" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
//
// // Defaults data-pattern-error: ALUNUMX
// $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALNUMX;
// $formElement[F_FE_DATA_PATTERN_ERROR] = 'custom pattern text';
// $result = $build->buildInput($formElement, 'name:1', '', $json);
// $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_DIGIT .
// '" data-pattern-error="' . $formElement[F_FE_DATA_PATTERN_ERROR] . '" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT .
// '" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
//
// // Defaults data-pattern-error: ALUNUMX
// $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALNUMX;
// $formElement[F_FE_DATA_PATTERN_ERROR] = 'custom pattern text';
// $result = $build->buildInput($formElement, 'name:1', '', $json);
// $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_ALNUMX .
// '" data-pattern-error="' . $formElement[F_FE_DATA_PATTERN_ERROR] . '" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT .
// '" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
//
// // Defaults data-pattern-error: ALUNUMX
// $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALNUMX;
// $formElement[F_FE_DATA_PATTERN_ERROR] = 'custom pattern text';
// $result = $build->buildInput($formElement, 'name:1', '', $json);
// $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_ALNUMX .
// '" data-pattern-error="' . $formElement[F_FE_DATA_PATTERN_ERROR] . '" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT .
// '" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
//
// // Defaults data-pattern-error: ALUNUMX
// $formElement[FE_CHECK_TYPE] = SANITIZE_ALLOW_ALNUMX;
// $formElement[F_FE_DATA_PATTERN_ERROR] = 'custom pattern text';
// $result = $build->buildInput($formElement, 'name:1', '', $json);
// $this->assertEquals('<input id="123" name="name:1" class="form-control" maxlength="255" type="input" value="" pattern="' . PATTERN_ALNUMX .
// '" data-pattern-error="' . $formElement[F_FE_DATA_PATTERN_ERROR] . '" data-required-error="' . F_FE_DATA_REQUIRED_ERROR_DEFAULT .
// '" data-error="' . F_FE_DATA_ERROR_DEFAULT . '" data-hidden="no" data-required="no" ><div class="help-block with-errors hidden"></div>', $result);
//
//
//